mirror of
https://github.com/MontFerret/ferret.git
synced 2025-02-09 13:38:35 +02:00
Added support of error supression to inline expressions (#671)
* Added support of error supression to inline expressions
This commit is contained in:
parent
658e929c5a
commit
2f399c669e
@ -28,6 +28,18 @@ func TestForTernaryExpression(t *testing.T) {
|
||||
So(string(out2), ShouldEqual, `true`)
|
||||
})
|
||||
|
||||
Convey("RETURN foo ? TRUE : (FOR i IN 1..5 T::FAIL() RETURN i*2)?", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
out1, err := c.MustCompile(`
|
||||
LET foo = FALSE
|
||||
RETURN foo ? TRUE : (FOR i IN 1..5 T::FAIL() RETURN i*2)?
|
||||
`).Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out1), ShouldEqual, `null`)
|
||||
})
|
||||
|
||||
Convey("RETURN foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2)", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
@ -48,6 +60,26 @@ func TestForTernaryExpression(t *testing.T) {
|
||||
So(string(out2), ShouldEqual, `[1,2,3,4,5]`)
|
||||
})
|
||||
|
||||
Convey("RETURN foo ? (FOR i IN 1..5 RETURN T::FAIL())? : (FOR i IN 1..5 RETURN T::FAIL())?", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
out1, err := c.MustCompile(`
|
||||
LET foo = FALSE
|
||||
RETURN foo ? (FOR i IN 1..5 RETURN T::FAIL()) : (FOR i IN 1..5 RETURN T::FAIL())?
|
||||
`).Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out1), ShouldEqual, `null`)
|
||||
|
||||
out2, err := c.MustCompile(`
|
||||
LET foo = TRUE
|
||||
RETURN foo ? (FOR i IN 1..5 RETURN T::FAIL())? : (FOR i IN 1..5 RETURN T::FAIL())
|
||||
`).Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out2), ShouldEqual, `null`)
|
||||
})
|
||||
|
||||
Convey("LET res = foo ? TRUE : (FOR i IN 1..5 RETURN i*2)", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
@ -91,6 +123,26 @@ func TestForTernaryExpression(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out2), ShouldEqual, `[1,2,3,4,5]`)
|
||||
})
|
||||
|
||||
Convey("LET res = (FOR i IN 1..5 RETURN T::FAIL())? ? TRUE : FALSE", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
out1, err := c.MustCompile(`
|
||||
LET res = (FOR i IN 1..5 RETURN T::FAIL())? ? TRUE : FALSE
|
||||
RETURN res
|
||||
`).Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out1), ShouldEqual, `false`)
|
||||
|
||||
out2, err := c.MustCompile(`
|
||||
LET res = (FOR i IN 1..5 RETURN i)? ? TRUE : FALSE
|
||||
RETURN res
|
||||
`).Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out2), ShouldEqual, `true`)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkForTernary(b *testing.B) {
|
||||
|
@ -22,6 +22,18 @@ func TestForTernaryWhileExpression(t *testing.T) {
|
||||
So(string(out1), ShouldEqual, `[]`)
|
||||
})
|
||||
|
||||
Convey("RETURN foo ? TRUE : (FOR i WHILE T::FAIL() RETURN i*2)?", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
out1, err := c.MustCompile(`
|
||||
LET foo = FALSE
|
||||
RETURN foo ? TRUE : (FOR i WHILE T::FAIL() RETURN i*2)?
|
||||
`).Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out1), ShouldEqual, `null`)
|
||||
})
|
||||
|
||||
Convey("RETURN foo ? TRUE : (FOR i WHILE F() < 10 RETURN i*2)", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
|
@ -104,6 +104,22 @@ func TestFunctionCall(t *testing.T) {
|
||||
So(string(out), ShouldEqual, `null`)
|
||||
})
|
||||
|
||||
Convey("Should handle errors when ? is used within a group", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN (FALSE OR T::FAIL())?
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(string(out), ShouldEqual, `null`)
|
||||
})
|
||||
|
||||
Convey("Should return NONE when error is handled", t, func() {
|
||||
c := compiler.New()
|
||||
c.RegisterFunction("ERROR", func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
@ -122,6 +138,38 @@ func TestFunctionCall(t *testing.T) {
|
||||
|
||||
So(string(out), ShouldEqual, `null`)
|
||||
})
|
||||
|
||||
Convey("Should be able to use FOR as an argument", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN FIRST((FOR i IN 1..10 RETURN i * 2))
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(string(out), ShouldEqual, `2`)
|
||||
})
|
||||
|
||||
Convey("Should be able to use FOR as arguments", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN UNION((FOR i IN 0..5 RETURN i), (FOR i IN 6..10 RETURN i))
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(string(out), ShouldEqual, `[0,1,2,3,4,5,6,7,8,9,10]`)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkFunctionCallArg1(b *testing.B) {
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/compiler"
|
||||
"github.com/MontFerret/ferret/pkg/runtime"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"testing"
|
||||
)
|
||||
@ -179,11 +181,35 @@ func TestLet(t *testing.T) {
|
||||
So(string(out), ShouldEqual, "[1,2,3]")
|
||||
})
|
||||
|
||||
Convey("Should compile LET i = (FOR i WHILE 0 > 1 RETURN i) RETURN i", t, func() {
|
||||
Convey("Should compile LET src = NONE LET i = (FOR i IN NONE RETURN i)? RETURN i == NONE", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
p, err := c.Compile(`
|
||||
LET i = (FOR i WHILE 0 > 1 RETURN i)
|
||||
LET src = NONE
|
||||
LET i = (FOR i IN src RETURN i)?
|
||||
RETURN i == NONE
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(p, ShouldHaveSameTypeAs, &runtime.Program{})
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, "true")
|
||||
})
|
||||
|
||||
Convey("Should compile LET i = (FOR i WHILE COUNTER() < 5 RETURN i) RETURN i", t, func() {
|
||||
c := compiler.New()
|
||||
counter := -1
|
||||
c.RegisterFunction("COUNTER", func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
counter++
|
||||
|
||||
return values.NewInt(counter), nil
|
||||
})
|
||||
|
||||
p, err := c.Compile(`
|
||||
LET i = (FOR i WHILE COUNTER() < 5 RETURN i)
|
||||
RETURN i
|
||||
`)
|
||||
|
||||
@ -193,7 +219,30 @@ func TestLet(t *testing.T) {
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, "[]")
|
||||
So(string(out), ShouldEqual, "[0,1,2,3,4]")
|
||||
})
|
||||
|
||||
Convey("Should compile LET i = (FOR i WHILE COUNTER() < 5 T::FAIL() RETURN i)? RETURN i == NONE", t, func() {
|
||||
c := compiler.New()
|
||||
counter := -1
|
||||
c.RegisterFunction("COUNTER", func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
counter++
|
||||
|
||||
return values.NewInt(counter), nil
|
||||
})
|
||||
|
||||
p, err := c.Compile(`
|
||||
LET i = (FOR i WHILE COUNTER() < 5 T::FAIL() RETURN i)?
|
||||
RETURN i == NONE
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(p, ShouldHaveSameTypeAs, &runtime.Program{})
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, "true")
|
||||
})
|
||||
|
||||
Convey("Should compile LET i = { items: [1,2,3]} FOR el IN i.items RETURN i", t, func() {
|
||||
@ -262,4 +311,30 @@ func TestLet(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, `"data"`)
|
||||
})
|
||||
|
||||
Convey("Should handle error from WAITFOR EVENT", t, func() {
|
||||
out, err := newCompilerWithObservable().MustCompile(`
|
||||
LET obj = X::CREATE()
|
||||
|
||||
LET res = (WAITFOR EVENT "event" IN obj 100)?
|
||||
|
||||
RETURN res == NONE
|
||||
`).Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, `true`)
|
||||
})
|
||||
|
||||
Convey("Should compare result of handled error", t, func() {
|
||||
out, err := newCompilerWithObservable().MustCompile(`
|
||||
LET obj = X::CREATE()
|
||||
|
||||
LET res = (WAITFOR EVENT "event" IN obj 100)? != NONE
|
||||
|
||||
RETURN res
|
||||
`).Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, `false`)
|
||||
})
|
||||
}
|
||||
|
@ -185,11 +185,7 @@ func (v *visitor) doVisitReturnExpression(ctx *fql.ReturnExpressionContext, scop
|
||||
var out core.Expression
|
||||
var err error
|
||||
|
||||
if exp := ctx.ForExpression(); exp != nil {
|
||||
out, err = v.doVisitForExpression(exp.(*fql.ForExpressionContext), scope.Fork())
|
||||
} else if exp := ctx.WaitForExpression(); exp != nil {
|
||||
out, err = v.doVisitWaitForExpressionContext(exp.(*fql.WaitForExpressionContext), scope)
|
||||
} else if exp := ctx.Expression(); exp != nil {
|
||||
if exp := ctx.Expression(); exp != nil {
|
||||
out, err = v.doVisitExpression(exp.(*fql.ExpressionContext), scope)
|
||||
} else {
|
||||
return nil, core.Error(ErrInvalidToken, ctx.GetText())
|
||||
@ -202,6 +198,36 @@ func (v *visitor) doVisitReturnExpression(ctx *fql.ReturnExpressionContext, scop
|
||||
return expressions.NewReturnExpression(v.getSourceMap(ctx), out)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitInlineHighLevelExpression(ctx *fql.InlineHighLevelExpressionContext, scope *scope) (core.Expression, error) {
|
||||
hlexpCtx := ctx.HighLevelExpression()
|
||||
|
||||
if hlexpCtx == nil {
|
||||
return nil, ErrInvalidToken
|
||||
}
|
||||
|
||||
exp, err := v.doVisitHighLevelExpression(hlexpCtx.(*fql.HighLevelExpressionContext), scope.Fork())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ctx.ErrorOperator() == nil {
|
||||
return exp, nil
|
||||
}
|
||||
|
||||
return expressions.SuppressErrors(exp)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitHighLevelExpression(ctx *fql.HighLevelExpressionContext, scope *scope) (core.Expression, error) {
|
||||
if exp := ctx.ForExpression(); exp != nil {
|
||||
return v.doVisitForExpression(exp.(*fql.ForExpressionContext), scope.Fork())
|
||||
} else if exp := ctx.WaitForExpression(); exp != nil {
|
||||
return v.doVisitWaitForExpressionContext(exp.(*fql.WaitForExpressionContext), scope)
|
||||
}
|
||||
|
||||
return nil, ErrInvalidToken
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *scope) (core.Expression, error) {
|
||||
var err error
|
||||
var valVarName string
|
||||
@ -599,6 +625,7 @@ func (v *visitor) doVisitCollectAggregateSelector(ctx *fql.CollectAggregateSelec
|
||||
|
||||
if fnCtx != nil {
|
||||
exp, err := v.doVisitFunctionCallExpression(fnCtx.(*fql.FunctionCallExpressionContext), scope)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -945,7 +972,7 @@ func (v *visitor) doVisitMemberExpressionSource(ctx *fql.MemberExpressionSourceC
|
||||
}
|
||||
|
||||
if fnCall := ctx.FunctionCall(); fnCall != nil {
|
||||
return v.doVisitFunctionCall(fnCall.(*fql.FunctionCallContext), false, scope)
|
||||
return v.doVisitFunctionCall(fnCall.(*fql.FunctionCallContext), scope)
|
||||
}
|
||||
|
||||
if objectLiteral := ctx.ObjectLiteral(); objectLiteral != nil {
|
||||
@ -1113,10 +1140,6 @@ func (v *visitor) doVisitVariableDeclaration(ctx *fql.VariableDeclarationContext
|
||||
|
||||
if exp := ctx.Expression(); exp != nil {
|
||||
init, err = v.doVisitExpression(ctx.Expression().(*fql.ExpressionContext), scope)
|
||||
} else if exp := ctx.ForExpression(); exp != nil {
|
||||
init, err = v.doVisitForExpression(exp.(*fql.ForExpressionContext), scope)
|
||||
} else if exp := ctx.WaitForExpression(); exp != nil {
|
||||
init, err = v.doVisitWaitForExpressionContext(exp.(*fql.WaitForExpressionContext), scope)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -1150,7 +1173,7 @@ func (v *visitor) doVisitRangeOperator(ctx *fql.RangeOperatorContext, scope *sco
|
||||
)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitFunctionCall(context *fql.FunctionCallContext, ignoreErrors bool, scope *scope) (core.Expression, error) {
|
||||
func (v *visitor) doVisitFunctionCall(context *fql.FunctionCallContext, scope *scope) (core.Expression, error) {
|
||||
args := make([]core.Expression, 0, 5)
|
||||
argsCtx := context.Arguments()
|
||||
|
||||
@ -1186,17 +1209,25 @@ func (v *visitor) doVisitFunctionCall(context *fql.FunctionCallContext, ignoreEr
|
||||
return expressions.NewFunctionCallExpression(
|
||||
v.getSourceMap(context),
|
||||
fun,
|
||||
ignoreErrors,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitFunctionCallExpression(context *fql.FunctionCallExpressionContext, scope *scope) (core.Expression, error) {
|
||||
return v.doVisitFunctionCall(
|
||||
exp, err := v.doVisitFunctionCall(
|
||||
context.FunctionCall().(*fql.FunctionCallContext),
|
||||
context.QuestionMark() != nil,
|
||||
scope,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if context.ErrorOperator() == nil {
|
||||
return exp, nil
|
||||
}
|
||||
|
||||
return expressions.SuppressErrors(exp)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitParamContext(context *fql.ParamContext, s *scope) (core.Expression, error) {
|
||||
@ -1417,13 +1448,23 @@ func (v *visitor) doVisitArrayOperator(ctx *fql.ExpressionContext, scope *scope)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitExpressionGroup(ctx *fql.ExpressionGroupContext, scope *scope) (core.Expression, error) {
|
||||
exp := ctx.Expression()
|
||||
expCtx := ctx.Expression()
|
||||
|
||||
if exp == nil {
|
||||
if expCtx == nil {
|
||||
return nil, ErrInvalidToken
|
||||
}
|
||||
|
||||
return v.doVisitExpression(exp.(*fql.ExpressionContext), scope)
|
||||
exp, err := v.doVisitExpression(expCtx.(*fql.ExpressionContext), scope)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ctx.ErrorOperator() == nil {
|
||||
return exp, nil
|
||||
}
|
||||
|
||||
return expressions.SuppressErrors(exp)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (core.Expression, error) {
|
||||
@ -1515,19 +1556,6 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c
|
||||
return v.doVisitNoneLiteral(exp.(*fql.NoneLiteralContext))
|
||||
}
|
||||
|
||||
if exp := ctx.QuestionMark(); exp != nil {
|
||||
exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return v.createTernaryOperator(
|
||||
v.getSourceMap(ctx),
|
||||
exps,
|
||||
scope,
|
||||
)
|
||||
}
|
||||
|
||||
if exp := ctx.RangeOperator(); exp != nil {
|
||||
return v.doVisitRangeOperator(exp.(*fql.RangeOperatorContext), scope)
|
||||
}
|
||||
@ -1536,6 +1564,10 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c
|
||||
return v.doVisitParamContext(param.(*fql.ParamContext), scope)
|
||||
}
|
||||
|
||||
if exp := ctx.InlineHighLevelExpression(); exp != nil {
|
||||
return v.doVisitInlineHighLevelExpression(exp.(*fql.InlineHighLevelExpressionContext), scope)
|
||||
}
|
||||
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
|
@ -40,13 +40,20 @@ bodyExpression
|
||||
;
|
||||
|
||||
variableDeclaration
|
||||
: Let Identifier Assign OpenParen (forExpression | waitForExpression) CloseParen
|
||||
| Let Identifier Assign expression
|
||||
: Let Identifier Assign expression
|
||||
;
|
||||
|
||||
returnExpression
|
||||
: Return Distinct? OpenParen (forExpression | waitForExpression) CloseParen
|
||||
| Return Distinct? expression
|
||||
: Return Distinct? expression
|
||||
;
|
||||
|
||||
inlineHighLevelExpression
|
||||
: OpenParen highLevelExpression CloseParen errorOperator?
|
||||
;
|
||||
|
||||
highLevelExpression
|
||||
: forExpression
|
||||
| waitForExpression
|
||||
;
|
||||
|
||||
forExpression
|
||||
@ -223,10 +230,6 @@ noneLiteral
|
||||
| None
|
||||
;
|
||||
|
||||
expressionGroup
|
||||
: OpenParen expression CloseParen
|
||||
;
|
||||
|
||||
expression
|
||||
: unaryOperator expression
|
||||
| expression multiplicativeOperator expression
|
||||
@ -238,9 +241,6 @@ expression
|
||||
| expression regexpOperator expression
|
||||
| expression logicalAndOperator expression
|
||||
| expression logicalOrOperator expression
|
||||
| expression QuestionMark OpenParen (forExpression | waitForExpression) CloseParen Colon OpenParen (forExpression | waitForExpression) CloseParen
|
||||
| expression QuestionMark expression Colon OpenParen (forExpression | waitForExpression) CloseParen
|
||||
| expression QuestionMark OpenParen (forExpression | waitForExpression) CloseParen Colon expression
|
||||
| expression QuestionMark expression? Colon expression
|
||||
| rangeOperator
|
||||
| stringLiteral
|
||||
@ -255,6 +255,11 @@ expression
|
||||
| variable
|
||||
| noneLiteral
|
||||
| expressionGroup
|
||||
| inlineHighLevelExpression
|
||||
;
|
||||
|
||||
expressionGroup
|
||||
: OpenParen expression CloseParen errorOperator?
|
||||
;
|
||||
|
||||
memberExpression
|
||||
@ -274,7 +279,7 @@ functionCall
|
||||
;
|
||||
|
||||
functionCallExpression
|
||||
: functionCall QuestionMark?
|
||||
: functionCall errorOperator?
|
||||
;
|
||||
|
||||
memberExpressionPath
|
||||
@ -282,6 +287,10 @@ memberExpressionPath
|
||||
| (QuestionMark Dot)? computedPropertyName
|
||||
;
|
||||
|
||||
errorOperator
|
||||
: QuestionMark
|
||||
;
|
||||
|
||||
functionIdentifier
|
||||
: Identifier
|
||||
| And
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -80,6 +80,20 @@ func (s *BaseFqlParserListener) EnterReturnExpression(ctx *ReturnExpressionConte
|
||||
// ExitReturnExpression is called when production returnExpression is exited.
|
||||
func (s *BaseFqlParserListener) ExitReturnExpression(ctx *ReturnExpressionContext) {}
|
||||
|
||||
// EnterInlineHighLevelExpression is called when production inlineHighLevelExpression is entered.
|
||||
func (s *BaseFqlParserListener) EnterInlineHighLevelExpression(ctx *InlineHighLevelExpressionContext) {
|
||||
}
|
||||
|
||||
// ExitInlineHighLevelExpression is called when production inlineHighLevelExpression is exited.
|
||||
func (s *BaseFqlParserListener) ExitInlineHighLevelExpression(ctx *InlineHighLevelExpressionContext) {
|
||||
}
|
||||
|
||||
// EnterHighLevelExpression is called when production highLevelExpression is entered.
|
||||
func (s *BaseFqlParserListener) EnterHighLevelExpression(ctx *HighLevelExpressionContext) {}
|
||||
|
||||
// ExitHighLevelExpression is called when production highLevelExpression is exited.
|
||||
func (s *BaseFqlParserListener) ExitHighLevelExpression(ctx *HighLevelExpressionContext) {}
|
||||
|
||||
// EnterForExpression is called when production forExpression is entered.
|
||||
func (s *BaseFqlParserListener) EnterForExpression(ctx *ForExpressionContext) {}
|
||||
|
||||
@ -284,18 +298,18 @@ func (s *BaseFqlParserListener) EnterNoneLiteral(ctx *NoneLiteralContext) {}
|
||||
// ExitNoneLiteral is called when production noneLiteral is exited.
|
||||
func (s *BaseFqlParserListener) ExitNoneLiteral(ctx *NoneLiteralContext) {}
|
||||
|
||||
// EnterExpressionGroup is called when production expressionGroup is entered.
|
||||
func (s *BaseFqlParserListener) EnterExpressionGroup(ctx *ExpressionGroupContext) {}
|
||||
|
||||
// ExitExpressionGroup is called when production expressionGroup is exited.
|
||||
func (s *BaseFqlParserListener) ExitExpressionGroup(ctx *ExpressionGroupContext) {}
|
||||
|
||||
// EnterExpression is called when production expression is entered.
|
||||
func (s *BaseFqlParserListener) EnterExpression(ctx *ExpressionContext) {}
|
||||
|
||||
// ExitExpression is called when production expression is exited.
|
||||
func (s *BaseFqlParserListener) ExitExpression(ctx *ExpressionContext) {}
|
||||
|
||||
// EnterExpressionGroup is called when production expressionGroup is entered.
|
||||
func (s *BaseFqlParserListener) EnterExpressionGroup(ctx *ExpressionGroupContext) {}
|
||||
|
||||
// ExitExpressionGroup is called when production expressionGroup is exited.
|
||||
func (s *BaseFqlParserListener) ExitExpressionGroup(ctx *ExpressionGroupContext) {}
|
||||
|
||||
// EnterMemberExpression is called when production memberExpression is entered.
|
||||
func (s *BaseFqlParserListener) EnterMemberExpression(ctx *MemberExpressionContext) {}
|
||||
|
||||
@ -326,6 +340,12 @@ func (s *BaseFqlParserListener) EnterMemberExpressionPath(ctx *MemberExpressionP
|
||||
// ExitMemberExpressionPath is called when production memberExpressionPath is exited.
|
||||
func (s *BaseFqlParserListener) ExitMemberExpressionPath(ctx *MemberExpressionPathContext) {}
|
||||
|
||||
// EnterErrorOperator is called when production errorOperator is entered.
|
||||
func (s *BaseFqlParserListener) EnterErrorOperator(ctx *ErrorOperatorContext) {}
|
||||
|
||||
// ExitErrorOperator is called when production errorOperator is exited.
|
||||
func (s *BaseFqlParserListener) ExitErrorOperator(ctx *ErrorOperatorContext) {}
|
||||
|
||||
// EnterFunctionIdentifier is called when production functionIdentifier is entered.
|
||||
func (s *BaseFqlParserListener) EnterFunctionIdentifier(ctx *FunctionIdentifierContext) {}
|
||||
|
||||
|
@ -47,6 +47,14 @@ func (v *BaseFqlParserVisitor) VisitReturnExpression(ctx *ReturnExpressionContex
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseFqlParserVisitor) VisitInlineHighLevelExpression(ctx *InlineHighLevelExpressionContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseFqlParserVisitor) VisitHighLevelExpression(ctx *HighLevelExpressionContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseFqlParserVisitor) VisitForExpression(ctx *ForExpressionContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
@ -183,11 +191,11 @@ func (v *BaseFqlParserVisitor) VisitNoneLiteral(ctx *NoneLiteralContext) interfa
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseFqlParserVisitor) VisitExpressionGroup(ctx *ExpressionGroupContext) interface{} {
|
||||
func (v *BaseFqlParserVisitor) VisitExpression(ctx *ExpressionContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseFqlParserVisitor) VisitExpression(ctx *ExpressionContext) interface{} {
|
||||
func (v *BaseFqlParserVisitor) VisitExpressionGroup(ctx *ExpressionGroupContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
@ -211,6 +219,10 @@ func (v *BaseFqlParserVisitor) VisitMemberExpressionPath(ctx *MemberExpressionPa
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseFqlParserVisitor) VisitErrorOperator(ctx *ErrorOperatorContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseFqlParserVisitor) VisitFunctionIdentifier(ctx *FunctionIdentifierContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
@ -37,6 +37,12 @@ type FqlParserListener interface {
|
||||
// EnterReturnExpression is called when entering the returnExpression production.
|
||||
EnterReturnExpression(c *ReturnExpressionContext)
|
||||
|
||||
// EnterInlineHighLevelExpression is called when entering the inlineHighLevelExpression production.
|
||||
EnterInlineHighLevelExpression(c *InlineHighLevelExpressionContext)
|
||||
|
||||
// EnterHighLevelExpression is called when entering the highLevelExpression production.
|
||||
EnterHighLevelExpression(c *HighLevelExpressionContext)
|
||||
|
||||
// EnterForExpression is called when entering the forExpression production.
|
||||
EnterForExpression(c *ForExpressionContext)
|
||||
|
||||
@ -139,12 +145,12 @@ type FqlParserListener interface {
|
||||
// EnterNoneLiteral is called when entering the noneLiteral production.
|
||||
EnterNoneLiteral(c *NoneLiteralContext)
|
||||
|
||||
// EnterExpressionGroup is called when entering the expressionGroup production.
|
||||
EnterExpressionGroup(c *ExpressionGroupContext)
|
||||
|
||||
// EnterExpression is called when entering the expression production.
|
||||
EnterExpression(c *ExpressionContext)
|
||||
|
||||
// EnterExpressionGroup is called when entering the expressionGroup production.
|
||||
EnterExpressionGroup(c *ExpressionGroupContext)
|
||||
|
||||
// EnterMemberExpression is called when entering the memberExpression production.
|
||||
EnterMemberExpression(c *MemberExpressionContext)
|
||||
|
||||
@ -160,6 +166,9 @@ type FqlParserListener interface {
|
||||
// EnterMemberExpressionPath is called when entering the memberExpressionPath production.
|
||||
EnterMemberExpressionPath(c *MemberExpressionPathContext)
|
||||
|
||||
// EnterErrorOperator is called when entering the errorOperator production.
|
||||
EnterErrorOperator(c *ErrorOperatorContext)
|
||||
|
||||
// EnterFunctionIdentifier is called when entering the functionIdentifier production.
|
||||
EnterFunctionIdentifier(c *FunctionIdentifierContext)
|
||||
|
||||
@ -235,6 +244,12 @@ type FqlParserListener interface {
|
||||
// ExitReturnExpression is called when exiting the returnExpression production.
|
||||
ExitReturnExpression(c *ReturnExpressionContext)
|
||||
|
||||
// ExitInlineHighLevelExpression is called when exiting the inlineHighLevelExpression production.
|
||||
ExitInlineHighLevelExpression(c *InlineHighLevelExpressionContext)
|
||||
|
||||
// ExitHighLevelExpression is called when exiting the highLevelExpression production.
|
||||
ExitHighLevelExpression(c *HighLevelExpressionContext)
|
||||
|
||||
// ExitForExpression is called when exiting the forExpression production.
|
||||
ExitForExpression(c *ForExpressionContext)
|
||||
|
||||
@ -337,12 +352,12 @@ type FqlParserListener interface {
|
||||
// ExitNoneLiteral is called when exiting the noneLiteral production.
|
||||
ExitNoneLiteral(c *NoneLiteralContext)
|
||||
|
||||
// ExitExpressionGroup is called when exiting the expressionGroup production.
|
||||
ExitExpressionGroup(c *ExpressionGroupContext)
|
||||
|
||||
// ExitExpression is called when exiting the expression production.
|
||||
ExitExpression(c *ExpressionContext)
|
||||
|
||||
// ExitExpressionGroup is called when exiting the expressionGroup production.
|
||||
ExitExpressionGroup(c *ExpressionGroupContext)
|
||||
|
||||
// ExitMemberExpression is called when exiting the memberExpression production.
|
||||
ExitMemberExpression(c *MemberExpressionContext)
|
||||
|
||||
@ -358,6 +373,9 @@ type FqlParserListener interface {
|
||||
// ExitMemberExpressionPath is called when exiting the memberExpressionPath production.
|
||||
ExitMemberExpressionPath(c *MemberExpressionPathContext)
|
||||
|
||||
// ExitErrorOperator is called when exiting the errorOperator production.
|
||||
ExitErrorOperator(c *ErrorOperatorContext)
|
||||
|
||||
// ExitFunctionIdentifier is called when exiting the functionIdentifier production.
|
||||
ExitFunctionIdentifier(c *FunctionIdentifierContext)
|
||||
|
||||
|
@ -37,6 +37,12 @@ type FqlParserVisitor interface {
|
||||
// Visit a parse tree produced by FqlParser#returnExpression.
|
||||
VisitReturnExpression(ctx *ReturnExpressionContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#inlineHighLevelExpression.
|
||||
VisitInlineHighLevelExpression(ctx *InlineHighLevelExpressionContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#highLevelExpression.
|
||||
VisitHighLevelExpression(ctx *HighLevelExpressionContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#forExpression.
|
||||
VisitForExpression(ctx *ForExpressionContext) interface{}
|
||||
|
||||
@ -139,12 +145,12 @@ type FqlParserVisitor interface {
|
||||
// Visit a parse tree produced by FqlParser#noneLiteral.
|
||||
VisitNoneLiteral(ctx *NoneLiteralContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#expressionGroup.
|
||||
VisitExpressionGroup(ctx *ExpressionGroupContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#expression.
|
||||
VisitExpression(ctx *ExpressionContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#expressionGroup.
|
||||
VisitExpressionGroup(ctx *ExpressionGroupContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#memberExpression.
|
||||
VisitMemberExpression(ctx *MemberExpressionContext) interface{}
|
||||
|
||||
@ -160,6 +166,9 @@ type FqlParserVisitor interface {
|
||||
// Visit a parse tree produced by FqlParser#memberExpressionPath.
|
||||
VisitMemberExpressionPath(ctx *MemberExpressionPathContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#errorOperator.
|
||||
VisitErrorOperator(ctx *ErrorOperatorContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by FqlParser#functionIdentifier.
|
||||
VisitFunctionIdentifier(ctx *FunctionIdentifierContext) interface{}
|
||||
|
||||
|
@ -46,11 +46,9 @@ func NewDefaultWhileIterator(mode WhileMode, predicate WhilePredicate) (Iterator
|
||||
}
|
||||
|
||||
func (iterator *WhileIterator) Next(ctx context.Context, scope *core.Scope) (*core.Scope, error) {
|
||||
counter := values.NewInt(iterator.pos)
|
||||
|
||||
// if it's Post conditional execution, step in always
|
||||
// Otherwise, it's not the first iteration
|
||||
if iterator.mode == WhileModePost || counter > 0 {
|
||||
if iterator.mode == WhileModePost || iterator.pos > 0 {
|
||||
doNext, err := iterator.predicate(ctx, scope)
|
||||
|
||||
if err != nil {
|
||||
@ -62,6 +60,7 @@ func (iterator *WhileIterator) Next(ctx context.Context, scope *core.Scope) (*co
|
||||
}
|
||||
}
|
||||
|
||||
counter := values.NewInt(iterator.pos)
|
||||
iterator.pos++
|
||||
|
||||
nextScope := scope.Fork()
|
||||
|
@ -7,23 +7,21 @@ import (
|
||||
)
|
||||
|
||||
type FunctionCallExpression struct {
|
||||
src core.SourceMap
|
||||
fun core.Function
|
||||
ignoreErrors bool
|
||||
args []core.Expression
|
||||
src core.SourceMap
|
||||
fun core.Function
|
||||
args []core.Expression
|
||||
}
|
||||
|
||||
func NewFunctionCallExpression(
|
||||
src core.SourceMap,
|
||||
fun core.Function,
|
||||
ignoreErrors bool,
|
||||
args ...core.Expression,
|
||||
) (*FunctionCallExpression, error) {
|
||||
if fun == nil {
|
||||
return nil, core.Error(core.ErrMissedArgument, "function")
|
||||
}
|
||||
|
||||
return &FunctionCallExpression{src, fun, ignoreErrors, args}, nil
|
||||
return &FunctionCallExpression{src, fun, args}, nil
|
||||
}
|
||||
|
||||
func (e *FunctionCallExpression) Arguments() []core.Expression {
|
||||
@ -31,18 +29,6 @@ func (e *FunctionCallExpression) Arguments() []core.Expression {
|
||||
}
|
||||
|
||||
func (e *FunctionCallExpression) Function() core.Function {
|
||||
if e.ignoreErrors {
|
||||
return func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
out, err := e.fun(ctx, args...)
|
||||
|
||||
if err != nil {
|
||||
return values.None, nil
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
return e.fun
|
||||
}
|
||||
|
||||
@ -63,7 +49,7 @@ func (e *FunctionCallExpression) Exec(ctx context.Context, scope *core.Scope) (c
|
||||
out, err := arg.Exec(ctx, scope)
|
||||
|
||||
if err != nil {
|
||||
return values.None, e.maybeError(core.SourceError(e.src, err))
|
||||
return values.None, core.SourceError(e.src, err)
|
||||
}
|
||||
|
||||
args[idx] = out
|
||||
@ -73,17 +59,9 @@ func (e *FunctionCallExpression) Exec(ctx context.Context, scope *core.Scope) (c
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return values.None, e.maybeError(core.SourceError(e.src, err))
|
||||
return values.None, core.SourceError(e.src, err)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *FunctionCallExpression) maybeError(err error) error {
|
||||
if !e.ignoreErrors {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ func TestFunctionCallExpression(t *testing.T) {
|
||||
|
||||
return values.True, nil
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
@ -48,7 +47,6 @@ func TestFunctionCallExpression(t *testing.T) {
|
||||
|
||||
return values.True, nil
|
||||
},
|
||||
false,
|
||||
args...,
|
||||
)
|
||||
|
||||
@ -75,7 +73,6 @@ func TestFunctionCallExpression(t *testing.T) {
|
||||
|
||||
return values.True, nil
|
||||
},
|
||||
false,
|
||||
args...,
|
||||
)
|
||||
|
||||
@ -96,11 +93,15 @@ func TestFunctionCallExpression(t *testing.T) {
|
||||
func(ctx context.Context, args ...core.Value) (value core.Value, e error) {
|
||||
return values.NewString("booo"), core.ErrNotImplemented
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
out, err := f.Exec(context.Background(), rootScope.Fork())
|
||||
|
||||
fse, err := expressions.SuppressErrors(f)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := fse.Exec(context.Background(), rootScope.Fork())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(out.Type().String(), ShouldEqual, types.None.String())
|
||||
|
32
pkg/runtime/expressions/suppressible.go
Normal file
32
pkg/runtime/expressions/suppressible.go
Normal file
@ -0,0 +1,32 @@
|
||||
package expressions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
)
|
||||
|
||||
type SuppressibleExpression struct {
|
||||
exp core.Expression
|
||||
}
|
||||
|
||||
func SuppressErrors(exp core.Expression) (core.Expression, error) {
|
||||
if exp == nil {
|
||||
return nil, core.Error(core.ErrMissedArgument, "expression")
|
||||
}
|
||||
|
||||
return &SuppressibleExpression{exp}, nil
|
||||
}
|
||||
|
||||
func (exp *SuppressibleExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) {
|
||||
return exp.Maybe(exp.exp.Exec(ctx, scope))
|
||||
}
|
||||
|
||||
func (exp *SuppressibleExpression) Maybe(value core.Value, err error) (core.Value, error) {
|
||||
if err != nil {
|
||||
return values.None, nil
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user