diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index df445299..f9907d53 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -59,9 +59,6 @@ func (c *FqlCompiler) Compile(query string) (program *runtime.Program, err error return nil, ErrEmptyQuery } - p := parser.New(query) - p.AddErrorListener(&errorListener{}) - defer func() { if r := recover(); r != nil { // find out exactly what the error was and set err @@ -78,6 +75,9 @@ func (c *FqlCompiler) Compile(query string) (program *runtime.Program, err error } }() + p := parser.New(query) + p.AddErrorListener(&errorListener{}) + l := newVisitor(query, c.funcs) res := p.Visit(l).(*result) diff --git a/pkg/runtime/program.go b/pkg/runtime/program.go index 6e7c8fca..c2f1de25 100644 --- a/pkg/runtime/program.go +++ b/pkg/runtime/program.go @@ -5,6 +5,7 @@ import ( "github.com/MontFerret/ferret/pkg/html" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" + "github.com/pkg/errors" ) type Program struct { @@ -28,7 +29,23 @@ func (p *Program) Source() string { return p.src } -func (p *Program) Run(ctx context.Context, setters ...Option) ([]byte, error) { +func (p *Program) Run(ctx context.Context, setters ...Option) (result []byte, err error) { + defer func() { + if r := recover(); r != nil { + // find out exactly what the error was and set err + switch x := r.(type) { + case string: + err = errors.New(x) + case error: + err = x + default: + err = errors.New("unknown panic") + } + + result = nil + } + }() + scope, closeFn := core.NewRootScope() defer closeFn() diff --git a/pkg/runtime/program_test.go b/pkg/runtime/program_test.go new file mode 100644 index 00000000..00c70324 --- /dev/null +++ b/pkg/runtime/program_test.go @@ -0,0 +1,25 @@ +package runtime_test + +import ( + "context" + "github.com/MontFerret/ferret/pkg/compiler" + "github.com/MontFerret/ferret/pkg/runtime/core" + . "github.com/smartystreets/goconvey/convey" + "testing" +) + +func TestProgram(t *testing.T) { + Convey("Should recover from panic", t, func() { + c := compiler.New() + c.RegisterFunction("panic", func(ctx context.Context, args ...core.Value) (core.Value, error) { + panic("test") + }) + + p := c.MustCompile(`RETURN PANIC()`) + + _, err := p.Run(context.Background()) + + So(err, ShouldBeError) + So(err.Error(), ShouldEqual, "test") + }) +}