Skip to content

Commit

Permalink
Implemented try-catch
Browse files Browse the repository at this point in the history
  • Loading branch information
ziflex committed Mar 29, 2024
1 parent 474d985 commit 03af1c7
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 118 deletions.
1 change: 1 addition & 0 deletions pkg/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func (c *Compiler) Compile(query string) (program *runtime.Program, err error) {
program.Arguments = l.arguments
program.Constants = l.constants
program.Locations = l.locations
program.CatchTable = l.catchTable

return program, err
}
Expand Down
122 changes: 29 additions & 93 deletions pkg/compiler/compiler_func_test.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
package compiler_test

import (
. "github.com/smartystreets/goconvey/convey"
"testing"
)

func TestFunctionCall(t *testing.T) {
RunUseCases(t, []UseCase{
//{
// "RETURN TYPENAME(1)",
// "int",
// nil,
//},
//{
// "WAIT(10) RETURN 1",
// 1,
// nil,
//},
//{
// "LET duration = 10 WAIT(duration) RETURN 1",
// 1,
// nil,
//},
{
"RETURN TYPENAME(1)",
"int",
nil,
},
{
"WAIT(10) RETURN 1",
1,
nil,
},
{
"LET duration = 10 WAIT(duration) RETURN 1",
1,
nil,
},
{
"RETURN (FALSE OR T::FAIL())?",
nil,
Expand All @@ -31,88 +32,23 @@ func TestFunctionCall(t *testing.T) {
nil,
nil,
},
{
`FOR i IN [1, 2, 3, 4]
LET duration = 10
WAIT(duration)
RETURN i * 2`,
[]int{2, 4, 6, 8},
ShouldEqualJSON,
},
//{
// `FOR i IN [1, 2, 3, 4]
// LET duration = 10
//
// WAIT(duration)
//
// RETURN i * 2`,
// []int{2, 4, 6, 8},
// ShouldEqualJSON,
// `RETURN FIRST((FOR i IN 1..10 RETURN i * 2))`,
// 2,
// nil,
//},
})

//
//Convey("Should handle errors when ? is used", t, func() {
// c := compiler.New()
// c.RegisterFunction("ERROR", func(ctx context.Context, args ...core.Value) (core.Value, error) {
// return values.None, errors.New("test error")
// })
//
// p, err := c.Compile(`
// RETURN ERROR()?
// `)
//
// So(err, ShouldBeNil)
//
// out, err := p.Run(context.Background())
//
// So(err, ShouldBeNil)
//
// 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) {
// return values.NewString("booo"), errors.New("test error")
// })
//
// p, err := c.Compile(`
// RETURN ERROR()?
// `)
//
// So(err, ShouldBeNil)
//
// out, err := p.Run(context.Background())
//
// So(err, ShouldBeNil)
//
// 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()
Expand Down
8 changes: 8 additions & 0 deletions pkg/compiler/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type (
loops []*loopScope
globals map[string]int
locals []variable
catchTable [][2]int
}
)

Expand All @@ -63,6 +64,7 @@ func newVisitor(src string) *visitor {
v.loops = make([]*loopScope, 0)
v.globals = make(map[string]int)
v.locals = make([]variable, 0)
v.catchTable = make([][2]int, 0)

return v
}
Expand Down Expand Up @@ -721,7 +723,13 @@ func (v *visitor) VisitPredicate(ctx *fql.PredicateContext) interface{} {
v.emit(runtime.OpLike)
}
} else if c := ctx.ExpressionAtom(); c != nil {
startCatch := len(v.bytecode)
c.Accept(v)

if c.ErrorOperator() != nil {
endCatch := len(v.bytecode)
v.catchTable = append(v.catchTable, [2]int{startCatch, endCatch})
}
}

return nil
Expand Down
11 changes: 6 additions & 5 deletions pkg/runtime/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import (
)

type Program struct {
Source *core.Source
Locations []core.Location
Bytecode []Opcode
Arguments []int
Constants []core.Value
Source *core.Source
Locations []core.Location
Bytecode []Opcode
Arguments []int
Constants []core.Value
CatchTable [][2]int
}

func (program *Program) Disassemble() string {
Expand Down
34 changes: 14 additions & 20 deletions pkg/runtime/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package runtime

import (
"context"
"errors"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/operators"
"github.com/MontFerret/ferret/pkg/runtime/values"
Expand All @@ -24,21 +23,16 @@ func NewVM(opts ...EnvironmentOption) *VM {
return vm
}

func (vm *VM) Run(ctx context.Context, program *Program) (res []byte, err error) {
defer func() {
if r := recover(); r != nil {
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
err = errors.New("unknown panic")
func (vm *VM) Run(ctx context.Context, program *Program) ([]byte, error) {
tryCatch := func(pos int) bool {
for _, pair := range program.CatchTable {
if pos >= pair[0] && pos <= pair[1] {
return true
}

program = nil
}
}()

return false
}

// TODO: Add code analysis to calculate the number of operands and variables
stack := NewStack(len(program.Bytecode), 8)
Expand Down Expand Up @@ -289,7 +283,7 @@ loop:

if err == nil {
stack.Push(res)
} else if op == OpCallOptional {
} else if op == OpCallOptional || tryCatch(vm.ip) {
stack.Push(values.None)
} else {
return nil, err
Expand All @@ -302,7 +296,7 @@ loop:

if err == nil {
stack.Push(res)
} else if op == OpCall1Optional {
} else if op == OpCall1Optional || tryCatch(vm.ip) {
stack.Push(values.None)
} else {
return nil, err
Expand All @@ -316,7 +310,7 @@ loop:

if err == nil {
stack.Push(res)
} else if op == OpCall2Optional {
} else if op == OpCall2Optional || tryCatch(vm.ip) {
stack.Push(values.None)
} else {
return nil, err
Expand All @@ -331,7 +325,7 @@ loop:

if err == nil {
stack.Push(res)
} else if op == OpCall3Optional {
} else if op == OpCall3Optional || tryCatch(vm.ip) {
stack.Push(values.None)
} else {
return nil, err
Expand All @@ -347,7 +341,7 @@ loop:

if err == nil {
stack.Push(res)
} else if op == OpCall4Optional {
} else if op == OpCall4Optional || tryCatch(vm.ip) {
stack.Push(values.None)
} else {
return nil, err
Expand All @@ -371,7 +365,7 @@ loop:

if err == nil {
stack.Push(res)
} else if op == OpCallNOptional {
} else if op == OpCallNOptional || tryCatch(vm.ip) {
stack.Push(values.None)
} else {
return nil, err
Expand Down

0 comments on commit 03af1c7

Please sign in to comment.