1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-08-15 20:02:56 +02:00

Refactored type system

This commit is contained in:
Tim Voronov
2025-04-08 16:31:14 -04:00
parent 1040e000e6
commit 59c67a7f4c
36 changed files with 456 additions and 444 deletions

View File

@@ -2,12 +2,11 @@ package compiler
import (
"errors"
goruntime "runtime"
"github.com/MontFerret/ferret/pkg/parser"
"github.com/MontFerret/ferret/pkg/runtime"
"github.com/MontFerret/ferret/pkg/stdlib"
//"github.com/MontFerret/ferret/pkg/stdlib"
)
type Compiler struct {
@@ -25,9 +24,9 @@ func New(setters ...Option) *Compiler {
}
if !opts.noStdlib {
if err := stdlib.RegisterLib(c.NamespaceContainer); err != nil {
panic(err)
}
//if err := stdlib.RegisterLib(c.NamespaceContainer); err != nil {
// panic(err)
//}
}
return c

View File

@@ -3,7 +3,6 @@ package compiler_test
import (
"context"
"fmt"
"github.com/MontFerret/ferret/pkg/runtime/internal"
"regexp"
"strconv"
"strings"
@@ -933,7 +932,7 @@ func TestForWhile(t *testing.T) {
`, []any{0, 1, 2, 2, 4, 6, 3, 6, 9, 12, 4, 8, 12, 16, 20}),
}, runtime.WithFunctions(map[string]core.Function{
"UNTIL": func(ctx context.Context, args ...core.Value) (core.Value, error) {
if untilCounter < int(internal.ToInt(args[0])) {
if untilCounter < int(core.ToIntSafe(ctx, args[0])) {
untilCounter++
return core.True, nil

View File

@@ -1,7 +1,6 @@
package compiler
import (
"github.com/MontFerret/ferret/pkg/runtime/internal"
"strconv"
"github.com/MontFerret/ferret/pkg/runtime"
@@ -58,7 +57,7 @@ func (st *SymbolTable) AddConstant(constant core.Value) runtime.Operand {
var hash uint64
isNone := constant == core.None
if internal.IsScalar(constant) {
if core.IsScalar(constant) {
hash = constant.Hash()
}

View File

@@ -266,29 +266,29 @@ func (v *visitor) VisitLimitClause(ctx *fql.LimitClauseContext) interface{} {
func (v *visitor) VisitCollectClause(ctx *fql.CollectClauseContext) interface{} {
// TODO: Undefine original loop variables
loop := v.loops.Loop()
//v.emitter.EmitAB(runtime.OpLoopPushIter, loop.Result, loop.Iterator)
//v.emitter.EmitJump(runtime.OpJump, loop.Jump-loop.JumpOffset)
//v.emitter.EmitA(runtime.OpClose, loop.Iterator)
// Allocate registers
collector := v.registers.Allocate(Temp)
collectorKey := v.registers.Allocate(Temp)
collectorVal := v.registers.Allocate(Temp)
// Init Grouping
// Create a new collector
v.emitter.EmitA(runtime.OpGroupPrep, collector)
// TODO: patch jump
if agr := ctx.CollectGrouping(); agr != nil {
selectors := agr.AllCollectSelector()
for _, selector := range selectors {
reg := selector.Expression().Accept(v).(runtime.Operand)
}
}
//loop := v.loops.Loop()
////v.emitter.EmitAB(runtime.OpLoopPushIter, loop.Result, loop.Iterator)
////v.emitter.EmitJump(runtime.OpJump, loop.Jump-loop.JumpOffset)
////v.emitter.EmitA(runtime.OpClose, loop.Iterator)
//
//// Allocate registers
//collector := v.registers.Allocate(Temp)
//collectorKey := v.registers.Allocate(Temp)
//collectorVal := v.registers.Allocate(Temp)
//
//// Init Grouping
//// Create a new collector
//v.emitter.EmitA(runtime.OpGroupPrep, collector)
//
//// TODO: patch jump
//
//if agr := ctx.CollectGrouping(); agr != nil {
// selectors := agr.AllCollectSelector()
//
// for _, selector := range selectors {
// reg := selector.Expression().Accept(v).(runtime.Operand)
// }
//}
return nil
}

View File

@@ -2,7 +2,6 @@ package drivers
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/internal"
"github.com/wI2L/jettison"
"github.com/MontFerret/ferret/pkg/runtime/core"
@@ -34,10 +33,6 @@ func (req *HTTPRequest) MarshalJSON() ([]byte, error) {
return jettison.MarshalOpts(requestMarshal(*req), jettison.NoHTMLEscaping())
}
func (req *HTTPRequest) Type() core.Type {
return HTTPRequestType
}
func (req *HTTPRequest) String() string {
return req.URL
}

View File

@@ -9,31 +9,31 @@ import (
"github.com/wI2L/jettison"
)
type arrayList struct {
type Array struct {
data []Value
}
func EmptyArray() List {
return &arrayList{data: make([]Value, 0)}
return &Array{data: make([]Value, 0)}
}
func NewArray(cap int) List {
return &arrayList{data: make([]Value, 0, cap)}
return &Array{data: make([]Value, 0, cap)}
}
func NewSizedArray(size int) List {
return &arrayList{data: make([]Value, size)}
return &Array{data: make([]Value, size)}
}
func NewArrayWith(values ...Value) List {
return &arrayList{data: values}
return &Array{data: values}
}
func (t *arrayList) MarshalJSON() ([]byte, error) {
func (t *Array) MarshalJSON() ([]byte, error) {
return jettison.MarshalOpts(t.data, jettison.NoHTMLEscaping())
}
func (t *arrayList) String() string {
func (t *Array) String() string {
marshaled, err := t.MarshalJSON()
if err != nil {
@@ -43,26 +43,26 @@ func (t *arrayList) String() string {
return string(marshaled)
}
func (t *arrayList) Compare(ctx context.Context, other Value) (int64, error) {
otherArr, ok := other.(*arrayList)
func (t *Array) Compare(other Value) int64 {
otherArr, ok := other.(*Array)
if !ok {
return CompareTypes(t, other), nil
return CompareTypes(t, other)
}
size := len(t.data)
otherArrSize := len(otherArr.data)
if size == 0 && otherArrSize == 0 {
return 0, nil
return 0
}
if size < otherArrSize {
return -1, nil
return -1
}
if size > otherArrSize {
return 1, nil
return 1
}
var res int64
@@ -71,23 +71,19 @@ func (t *arrayList) Compare(ctx context.Context, other Value) (int64, error) {
thisVal := t.data[i]
otherVal := otherArr.data[i]
comp, err := CompareValues(ctx, thisVal, otherVal)
if err != nil {
return 0, err
}
comp := CompareValues(thisVal, otherVal)
if comp != 0 {
return comp, nil
return comp
}
res = comp
}
return res, nil
return res
}
func (t *arrayList) Unwrap() interface{} {
func (t *Array) Unwrap() interface{} {
arr := make([]interface{}, len(t.data))
for idx, val := range t.data {
@@ -97,7 +93,7 @@ func (t *arrayList) Unwrap() interface{} {
return arr
}
func (t *arrayList) Hash() uint64 {
func (t *Array) Hash() uint64 {
h := fnv.New64a()
h.Write([]byte("array:"))
@@ -121,7 +117,7 @@ func (t *arrayList) Hash() uint64 {
return h.Sum64()
}
func (t *arrayList) Copy() Value {
func (t *Array) Copy() Value {
ctx := context.Background()
c := NewArray(len(t.data))
@@ -132,9 +128,9 @@ func (t *arrayList) Copy() Value {
return c
}
func (t *arrayList) Clone(ctx context.Context) (Cloneable, error) {
func (t *Array) Clone(ctx context.Context) (Cloneable, error) {
size := len(t.data)
res := &arrayList{data: make([]Value, size)}
res := &Array{data: make([]Value, size)}
var value Value
@@ -152,19 +148,19 @@ func (t *arrayList) Clone(ctx context.Context) (Cloneable, error) {
return res, nil
}
func (t *arrayList) Iterate(_ context.Context) (Iterator, error) {
func (t *Array) Iterate(_ context.Context) (Iterator, error) {
return NewArrayIterator(t), nil
}
func (t *arrayList) Length(_ context.Context) (Int, error) {
func (t *Array) Length(_ context.Context) (Int, error) {
return Int(len(t.data)), nil
}
func (t *arrayList) IsEmpty(_ context.Context) (Boolean, error) {
func (t *Array) IsEmpty(_ context.Context) (Boolean, error) {
return len(t.data) == 0, nil
}
func (t *arrayList) Contains(ctx context.Context, value Value) (Boolean, error) {
func (t *Array) Contains(ctx context.Context, value Value) (Boolean, error) {
idx, err := t.IndexOf(ctx, value)
if err != nil {
@@ -174,13 +170,9 @@ func (t *arrayList) Contains(ctx context.Context, value Value) (Boolean, error)
return idx >= 0, nil
}
func (t *arrayList) IndexOf(ctx context.Context, item Value) (Int, error) {
func (t *Array) IndexOf(_ context.Context, item Value) (Int, error) {
for idx, el := range t.data {
comp, err := CompareValues(ctx, item, el)
if err != nil {
return -1, err
}
comp := CompareValues(item, el)
if comp == 0 {
return Int(idx), nil
@@ -190,7 +182,7 @@ func (t *arrayList) IndexOf(ctx context.Context, item Value) (Int, error) {
return -1, nil
}
func (t *arrayList) Get(_ context.Context, idx Int) (Value, error) {
func (t *Array) Get(_ context.Context, idx Int) (Value, error) {
l := Int(len(t.data) - 1)
if l < 0 {
@@ -204,7 +196,7 @@ func (t *arrayList) Get(_ context.Context, idx Int) (Value, error) {
return t.data[idx], nil
}
func (t *arrayList) First(_ context.Context) (Value, error) {
func (t *Array) First(_ context.Context) (Value, error) {
if len(t.data) > 0 {
return t.data[0], nil
}
@@ -212,7 +204,7 @@ func (t *arrayList) First(_ context.Context) (Value, error) {
return None, nil
}
func (t *arrayList) Last(_ context.Context) (Value, error) {
func (t *Array) Last(_ context.Context) (Value, error) {
size := len(t.data)
if size > 1 {
@@ -224,7 +216,7 @@ func (t *arrayList) Last(_ context.Context) (Value, error) {
return None, nil
}
func (t *arrayList) Find(ctx context.Context, predicate IndexedPredicate) (List, error) {
func (t *Array) Find(ctx context.Context, predicate IndexedPredicate) (List, error) {
result := NewArray(len(t.data))
size := Int(len(t.data))
@@ -244,7 +236,7 @@ func (t *arrayList) Find(ctx context.Context, predicate IndexedPredicate) (List,
return result, nil
}
func (t *arrayList) FindOne(ctx context.Context, predicate IndexedPredicate) (Value, Boolean, error) {
func (t *Array) FindOne(ctx context.Context, predicate IndexedPredicate) (Value, Boolean, error) {
size := Int(len(t.data))
for idx := Int(0); idx < size; idx++ {
@@ -263,7 +255,7 @@ func (t *arrayList) FindOne(ctx context.Context, predicate IndexedPredicate) (Va
return None, false, nil
}
func (t *arrayList) Slice(_ context.Context, start, end Int) (List, error) {
func (t *Array) Slice(_ context.Context, start, end Int) (List, error) {
length := Int(len(t.data))
if start >= length {
@@ -274,59 +266,45 @@ func (t *arrayList) Slice(_ context.Context, start, end Int) (List, error) {
end = length
}
result := new(arrayList)
result := new(Array)
result.data = t.data[start:end]
return result, nil
}
func (t *arrayList) Sort(ctx context.Context, ascending Boolean) (List, error) {
func (t *Array) Sort(ctx context.Context, ascending Boolean) (List, error) {
var pivot int64 = -1
if ascending {
pivot = 1
}
return t.SortWith(ctx, func(c context.Context, first, second Value) (int64, error) {
comp, err := CompareValues(c, first, second)
res, _ := t.SortWith(ctx, func(first, second Value) int64 {
comp := CompareValues(first, second)
if err != nil {
return 0, err
}
return pivot * comp, nil
return pivot * comp
})
return res, nil
}
func (t *arrayList) SortWith(ctx context.Context, comparator Comparator) (List, error) {
func (t *Array) SortWith(_ context.Context, comparator Comparator) (List, error) {
c := make([]Value, len(t.data))
copy(c, t.data)
var err error
sort.SliceStable(c, func(i, j int) bool {
comp, e := comparator(ctx, c[i], c[j])
if e != nil {
err = e
return true
}
comp := comparator(c[i], c[j])
return comp == 0
})
if err != nil {
return nil, err
}
res := new(arrayList)
res := new(Array)
res.data = c
return res, nil
}
func (t *arrayList) ForEach(ctx context.Context, predicate IndexedPredicate) error {
func (t *Array) ForEach(ctx context.Context, predicate IndexedPredicate) error {
size := Int(len(t.data))
for idx := Int(0); idx < size; idx++ {
@@ -345,13 +323,13 @@ func (t *arrayList) ForEach(ctx context.Context, predicate IndexedPredicate) err
return nil
}
func (t *arrayList) Add(_ context.Context, value Value) error {
func (t *Array) Add(_ context.Context, value Value) error {
t.data = append(t.data, value)
return nil
}
func (t *arrayList) Set(_ context.Context, idx Int, value Value) error {
func (t *Array) Set(_ context.Context, idx Int, value Value) error {
last := Int(len(t.data) - 1)
if last >= idx {
@@ -363,19 +341,19 @@ func (t *arrayList) Set(_ context.Context, idx Int, value Value) error {
return Error(ErrInvalidOperation, "out of bounds")
}
func (t *arrayList) Insert(_ context.Context, idx Int, value Value) error {
func (t *Array) Insert(_ context.Context, idx Int, value Value) error {
t.data = append(t.data[:idx], append([]Value{value}, t.data[idx:]...)...)
return nil
}
func (t *arrayList) Clear(_ context.Context) error {
func (t *Array) Clear(_ context.Context) error {
t.data = make([]Value, 0)
return nil
}
func (t *arrayList) Remove(ctx context.Context, value Value) error {
func (t *Array) Remove(ctx context.Context, value Value) error {
idx, err := t.IndexOf(ctx, value)
if err != nil {
@@ -391,7 +369,7 @@ func (t *arrayList) Remove(ctx context.Context, value Value) error {
return err
}
func (t *arrayList) RemoveAt(_ context.Context, idx Int) (Value, error) {
func (t *Array) RemoveAt(_ context.Context, idx Int) (Value, error) {
edge := Int(len(t.data) - 1)
if idx > edge {
@@ -405,7 +383,7 @@ func (t *arrayList) RemoveAt(_ context.Context, idx Int) (Value, error) {
return item, nil
}
func (t *arrayList) Swap(_ context.Context, i, j Int) error {
func (t *Array) Swap(_ context.Context, i, j Int) error {
t.data[i], t.data[j] = t.data[j], t.data[i]
return nil

View File

@@ -5,12 +5,12 @@ import (
)
type ArrayIterator struct {
values *arrayList
values *Array
length int
pos int
}
func NewArrayIterator(values *arrayList) Iterator {
func NewArrayIterator(values *Array) Iterator {
return &ArrayIterator{values: values, length: len(values.data), pos: 0}
}

View File

@@ -506,7 +506,7 @@ func TestArray(t *testing.T) {
),
)
clone := arr.Clone().(*core.arrayList)
clone := arr.Clone().(*core.Array)
So(arr.Length(), ShouldEqual, clone.Length())
So(arr.Compare(clone), ShouldEqual, 0)
@@ -522,7 +522,7 @@ func TestArray(t *testing.T) {
NewInt(5),
)
clone := arr.Clone().(*core.arrayList)
clone := arr.Clone().(*core.Array)
arr.Push(NewInt(6))
@@ -541,12 +541,12 @@ func TestArray(t *testing.T) {
// ),
// )
//
// clone := arr.Clone().(*values.arrayList)
// clone := arr.Clone().(*values.Array)
//
// nestedInArr := arr.Get(values.NewInt(0)).(*values.arrayList)
// nestedInArr := arr.Get(values.NewInt(0)).(*values.Array)
// nestedInArr.Push(values.NewInt(5))
//
// nestedInClone := clone.Get(values.NewInt(0)).(*values.arrayList)
// nestedInClone := clone.Get(values.NewInt(0)).(*values.Array)
//
// So(nestedInArr.CompareValues(nestedInClone), ShouldNotEqual, 0)
//})

View File

@@ -80,7 +80,7 @@ func AssertMap(input Value) error {
if !ok {
return TypeError(
input,
"map",
TypeMap,
)
}

View File

@@ -31,10 +31,6 @@ func (b Binary) MarshalJSON() ([]byte, error) {
)
}
func (b Binary) Type() string {
return TypeBinary
}
func (b Binary) String() string {
return string(b)
}
@@ -61,33 +57,33 @@ func (b Binary) Copy() Value {
return NewBinary(c)
}
func (b Binary) Length(_ context.Context) (int, error) {
return len(b), nil
func (b Binary) Length(_ context.Context) (Int, error) {
return Int(len(b)), nil
}
func (b Binary) Compare(_ context.Context, other Value) (int64, error) {
func (b Binary) Compare(other Value) int64 {
otherBin, ok := other.(Binary)
if !ok {
return CompareTypes(b, other), nil
return CompareTypes(b, other)
}
size := len(b)
otherSize := len(otherBin)
if size > otherSize {
return 1, nil
return 1
} else if size < otherSize {
return -1, nil
return -1
}
for i := 0; i < size; i++ {
if b[i] > otherBin[i] {
return 1, nil
return 1
} else if b[i] < otherBin[i] {
return -1, nil
return -1
}
}
return 0, nil
return 0
}

View File

@@ -1,7 +1,6 @@
package core
import (
"context"
"hash/fnv"
"strings"
@@ -63,10 +62,6 @@ func MustParseBoolean(input interface{}) Boolean {
return res
}
func (t Boolean) Type() string {
return TypeBoolean
}
func (t Boolean) MarshalJSON() ([]byte, error) {
return jettison.MarshalOpts(bool(t), jettison.NoHTMLEscaping())
}
@@ -95,20 +90,20 @@ func (t Boolean) Copy() Value {
return t
}
func (t Boolean) Compare(_ context.Context, other Value) (int64, error) {
func (t Boolean) Compare(other Value) int64 {
otherBool, ok := other.(Boolean)
if !ok {
return CompareTypes(t, other), nil
return CompareTypes(t, other)
}
if t == otherBool {
return 0, nil
return 0
}
if !t && otherBool {
return -1, nil
return -1
}
return +1, nil
return +1
}

View File

@@ -1,7 +1,6 @@
package core
import (
"context"
"hash/fnv"
"time"
@@ -92,20 +91,20 @@ func (dt DateTime) Copy() Value {
return NewDateTime(dt.Time)
}
func (dt DateTime) Compare(_ context.Context, other Value) (int64, error) {
func (dt DateTime) Compare(other Value) int64 {
otherDt, ok := other.(DateTime)
if !ok {
return CompareTypes(dt, other), nil
return CompareTypes(dt, other)
}
if dt.After(otherDt.Time) {
return 1, nil
return 1
}
if dt.Before(otherDt.Time) {
return -1, nil
return -1
}
return 0, nil
return 0
}

View File

@@ -20,15 +20,12 @@ var (
ErrTimeout = errors.New("operation timed out")
ErrNotImplemented = errors.New("not implemented")
ErrNotSupported = errors.New("not supported")
ErrNoMoreData = errors.New("no more data")
ErrInvalidPath = errors.New("cannot read property")
ErrDone = errors.New("operation done")
)
const typeErrorTemplate = "expected %s, but got %s"
func TypeError(value Value, expected ...string) error {
actual := value.Type()
actual := Reflect(value)
if len(expected) == 0 {
return Error(ErrInvalidType, actual)
@@ -68,7 +65,3 @@ func Errors(err ...error) error {
return errors.New(message)
}
func IsDone(err error) bool {
return err == ErrDone
}

View File

@@ -1,7 +1,6 @@
package core
import (
"context"
"encoding/binary"
"fmt"
"hash/fnv"
@@ -108,31 +107,31 @@ func (f Float) Copy() Value {
return f
}
func (f Float) Compare(_ context.Context, other Value) (int64, error) {
func (f Float) Compare(other Value) int64 {
switch otherVal := other.(type) {
case Float:
if f == otherVal {
return 0, nil
return 0
}
if f < otherVal {
return -1, nil
return -1
}
return +1, nil
return +1
case Int:
f := Float(otherVal)
if f == f {
return 0, nil
return 0
}
if f < f {
return -1, nil
return -1
}
return +1, nil
return +1
default:
return CompareTypes(f, other), nil
return CompareTypes(f, other)
}
}

View File

@@ -270,7 +270,7 @@ func ToMap(ctx context.Context, input Value) Map {
switch value := input.(type) {
case Map:
return value
case *arrayList:
case *Array:
obj := NewObject()
for i, v := range value.data {
@@ -433,13 +433,13 @@ func ToInt(ctx context.Context, input Value) (Int, error) {
item, _, err := iterator.Next(ctx)
if err != nil {
continue
return ZeroInt, err
}
i, err := ToInt(ctx, item)
if err != nil {
continue
return ZeroInt, err
}
res += i
@@ -451,6 +451,20 @@ func ToInt(ctx context.Context, input Value) (Int, error) {
}
}
func ToIntSafe(ctx context.Context, input Value) Int {
result, err := ToInt(ctx, input)
if err != nil {
return ZeroInt
}
if result > 0 {
return result
}
return ZeroInt
}
func ToIntDefault(ctx context.Context, input Value, defaultValue Int) (Int, error) {
result, err := ToInt(ctx, input)
@@ -604,30 +618,6 @@ func Positive(input Value) Value {
}
}
func Contains(ctx context.Context, input Value, value Value) Boolean {
switch val := input.(type) {
case List:
contains, err := val.Contains(ctx, value)
if err != nil {
return False
}
return contains
case Map:
containsValue, err := val.ContainsValue(ctx, value)
if err != nil {
return False
}
return containsValue
case String:
return Boolean(strings.Contains(val.String(), value.String()))
default:
return false
}
}
func ToNumberOrString(input Value) Value {
switch value := input.(type) {
case Int, Float, String:
@@ -637,57 +627,6 @@ func ToNumberOrString(input Value) Value {
}
}
func ToNumberOnly(ctx context.Context, input Value) (Value, error) {
switch value := input.(type) {
case Int, Float:
return value, nil
case String:
if strings.Contains(value.String(), ".") {
return ToFloat(ctx, input)
}
return ToInt(ctx, input)
case Iterable:
iterator, err := value.Iterate(ctx)
if err != nil {
return ZeroInt, err
}
i := ZeroInt
f := ZeroFloat
for hasNext, err := iterator.HasNext(ctx); hasNext && err == nil; {
val, _, err := iterator.Next(ctx)
if err != nil {
continue
}
out, err := ToNumberOnly(ctx, val)
if err != nil {
return ZeroInt, err
}
switch item := out.(type) {
case Int:
i += item
case Float:
f += item
}
}
if f == 0 {
return i, nil
}
return Float(i) + f, nil
default:
return ToInt(ctx, input)
}
}
func CompareStrings(a, b String) Int {
return Int(strings.Compare(a.String(), b.String()))
}

View File

@@ -12,7 +12,7 @@ import (
)
type CustomValue struct {
properties map[Value]Value
properties map[core.Value]core.Value
}
type DummyStruct struct{}
@@ -213,11 +213,11 @@ func TestHelpers(t *testing.T) {
So(core.ToFloat(False), ShouldEqual, NewFloat(0))
})
Convey("Should convert arrayList with single item", func() {
Convey("Should convert Array with single item", func() {
So(core.ToFloat(NewArrayWith(NewFloat(1))), ShouldEqual, NewFloat(1))
})
Convey("Should convert arrayList with multiple items", func() {
Convey("Should convert Array with multiple items", func() {
arg := NewArrayWith(NewFloat(1), NewFloat(1))
So(core.ToFloat(arg), ShouldEqual, NewFloat(2))
@@ -272,11 +272,11 @@ func TestHelpers(t *testing.T) {
So(core.ToInt(False), ShouldEqual, NewInt(0))
})
Convey("Should convert arrayList with single item", func() {
Convey("Should convert Array with single item", func() {
So(core.ToInt(NewArrayWith(NewFloat(1))), ShouldEqual, NewInt(1))
})
Convey("Should convert arrayList with multiple items", func() {
Convey("Should convert Array with multiple items", func() {
arg := NewArrayWith(NewFloat(1), NewFloat(1))
So(core.ToInt(arg), ShouldEqual, NewFloat(2))

View File

@@ -1,7 +1,6 @@
package core
import (
"context"
"encoding/binary"
"hash/fnv"
"strconv"
@@ -98,33 +97,33 @@ func (i Int) Copy() Value {
return i
}
func (i Int) Compare(_ context.Context, other Value) (int64, error) {
func (i Int) Compare(other Value) int64 {
switch otherVal := other.(type) {
case Int:
if i == otherVal {
return 0, nil
return 0
}
if i < otherVal {
return -1, nil
return -1
}
return +1, nil
return +1
case Float:
f := Float(i)
if f == otherVal {
return 0, nil
return 0
}
if f < otherVal {
return -1, nil
return -1
}
return +1, nil
return +1
default:
return CompareTypes(i, other), nil
return CompareTypes(i, other)
}
}

View File

@@ -18,8 +18,6 @@ type (
items List
pos Int
}
mapIterator struct{}
)
func ForEach(ctx context.Context, iter Iterator, predicate func(value Value, key Value) bool) error {

View File

@@ -15,7 +15,7 @@ type (
value Value
}
hashMap struct {
Object struct {
data map[string]Value
}
)
@@ -25,11 +25,11 @@ func NewObjectProperty(name string, value Value) *ObjectProperty {
}
func NewObject() Map {
return &hashMap{make(map[string]Value)}
return &Object{make(map[string]Value)}
}
func NewObjectWith(props ...*ObjectProperty) Map {
obj := &hashMap{make(map[string]Value)}
obj := &Object{make(map[string]Value)}
for _, prop := range props {
obj.data[prop.key] = prop.value
@@ -38,15 +38,15 @@ func NewObjectWith(props ...*ObjectProperty) Map {
return obj
}
func (t *hashMap) Type() string {
func (t *Object) Type() string {
return "object"
}
func (t *hashMap) MarshalJSON() ([]byte, error) {
func (t *Object) MarshalJSON() ([]byte, error) {
return jettison.MarshalOpts(t.data, jettison.NoHTMLEscaping())
}
func (t *hashMap) String() string {
func (t *Object) String() string {
marshaled, err := t.MarshalJSON()
if err != nil {
@@ -59,27 +59,26 @@ func (t *hashMap) String() string {
// Compare compares the source object with other core.Value
// The behavior of the Compare is similar
// to the comparison of objects in ArangoDB
func (t *hashMap) Compare(ctx context.Context, other Value) (int64, error) {
otherObject, ok := other.(*hashMap)
func (t *Object) Compare(other Value) int64 {
otherObject, ok := other.(*Object)
if !ok {
// TODO: Maybe we should return an error here
return CompareTypes(t, other), nil
return CompareTypes(t, other)
}
size := len(t.data)
otherSize := len(otherObject.data)
if size == 0 && otherSize == 0 {
return 0, nil
return 0
}
if size < otherSize {
return -1, nil
return -1
}
if size > otherSize {
return 1, nil
return 1
}
var res int64
@@ -95,10 +94,9 @@ func (t *hashMap) Compare(ctx context.Context, other Value) (int64, error) {
otherKeys := make([]string, 0, otherSize)
_ = otherObject.ForEach(ctx, func(_ context.Context, value, k Value) (Boolean, error) {
otherKeys = append(otherKeys, k.String())
return true, nil
})
for k := range otherObject.data {
otherKeys = append(otherKeys, k)
}
sortedOther := sort.StringSlice(otherKeys)
sortedOther.Sort()
@@ -110,15 +108,9 @@ func (t *hashMap) Compare(ctx context.Context, other Value) (int64, error) {
tKey, otherKey = sortedT[i], sortedOther[i]
if tKey == otherKey {
tVal, _ = t.Get(ctx, NewString(tKey))
otherVal, _ = otherObject.Get(ctx, NewString(tKey))
comp, err := CompareValues(ctx, tVal, otherVal)
if err != nil {
return 0, err
}
res = comp
tVal, _ = t.data[tKey]
otherVal, _ = otherObject.data[tKey]
res = CompareValues(tVal, otherVal)
continue
}
@@ -132,10 +124,10 @@ func (t *hashMap) Compare(ctx context.Context, other Value) (int64, error) {
break
}
return res, nil
return res
}
func (t *hashMap) Unwrap() interface{} {
func (t *Object) Unwrap() interface{} {
obj := make(map[string]interface{})
for key, val := range t.data {
@@ -145,7 +137,7 @@ func (t *hashMap) Unwrap() interface{} {
return obj
}
func (t *hashMap) Hash() uint64 {
func (t *Object) Hash() uint64 {
h := fnv.New64a()
h.Write([]byte("object:"))
@@ -183,8 +175,8 @@ func (t *hashMap) Hash() uint64 {
return h.Sum64()
}
func (t *hashMap) Copy() Value {
c := &hashMap{make(map[string]Value)}
func (t *Object) Copy() Value {
c := &Object{make(map[string]Value)}
for k, v := range t.data {
c.data[k] = v
@@ -193,8 +185,8 @@ func (t *hashMap) Copy() Value {
return c
}
func (t *hashMap) Clone(ctx context.Context) (Cloneable, error) {
cloned := &hashMap{make(map[string]Value)}
func (t *Object) Clone(ctx context.Context) (Cloneable, error) {
cloned := &Object{make(map[string]Value)}
var value Value
@@ -221,15 +213,15 @@ func (t *hashMap) Clone(ctx context.Context) (Cloneable, error) {
return cloned, nil
}
func (t *hashMap) Length(_ context.Context) (Int, error) {
func (t *Object) Length(_ context.Context) (Int, error) {
return Int(len(t.data)), nil
}
func (t *hashMap) IsEmpty(_ context.Context) (Boolean, error) {
func (t *Object) IsEmpty(_ context.Context) (Boolean, error) {
return len(t.data) == 0, nil
}
func (t *hashMap) Keys(_ context.Context) ([]Value, error) {
func (t *Object) Keys(_ context.Context) ([]Value, error) {
keys := make([]Value, 0, len(t.data))
for k := range t.data {
@@ -239,7 +231,7 @@ func (t *hashMap) Keys(_ context.Context) ([]Value, error) {
return keys, nil
}
func (t *hashMap) Values(_ context.Context) ([]Value, error) {
func (t *Object) Values(_ context.Context) ([]Value, error) {
keys := make([]Value, 0, len(t.data))
for _, v := range t.data {
@@ -249,7 +241,7 @@ func (t *hashMap) Values(_ context.Context) ([]Value, error) {
return keys, nil
}
func (t *hashMap) ForEach(ctx context.Context, predicate KeyedPredicate) error {
func (t *Object) ForEach(ctx context.Context, predicate KeyedPredicate) error {
for key, val := range t.data {
doContinue, err := predicate(ctx, val, String(key))
@@ -265,7 +257,7 @@ func (t *hashMap) ForEach(ctx context.Context, predicate KeyedPredicate) error {
return nil
}
func (t *hashMap) Find(ctx context.Context, predicate KeyedPredicate) (List, error) {
func (t *Object) Find(ctx context.Context, predicate KeyedPredicate) (List, error) {
res := NewArray(len(t.data))
for key, val := range t.data {
@@ -283,7 +275,7 @@ func (t *hashMap) Find(ctx context.Context, predicate KeyedPredicate) (List, err
return res, nil
}
func (t *hashMap) FindOne(ctx context.Context, predicate KeyedPredicate) (Value, Boolean, error) {
func (t *Object) FindOne(ctx context.Context, predicate KeyedPredicate) (Value, Boolean, error) {
for key, val := range t.data {
res, err := predicate(ctx, val, String(key))
@@ -299,19 +291,15 @@ func (t *hashMap) FindOne(ctx context.Context, predicate KeyedPredicate) (Value,
return None, false, nil
}
func (t *hashMap) ContainsKey(_ context.Context, key Value) (Boolean, error) {
func (t *Object) ContainsKey(_ context.Context, key Value) (Boolean, error) {
_, exists := t.data[key.String()]
return Boolean(exists), nil
}
func (t *hashMap) ContainsValue(ctx context.Context, target Value) (Boolean, error) {
func (t *Object) ContainsValue(_ context.Context, target Value) (Boolean, error) {
for _, val := range t.data {
res, err := CompareValues(ctx, target, val)
if err != nil {
return false, err
}
res := CompareValues(target, val)
if res == 0 {
return true, nil
@@ -321,7 +309,7 @@ func (t *hashMap) ContainsValue(ctx context.Context, target Value) (Boolean, err
return false, nil
}
func (t *hashMap) Get(_ context.Context, key Value) (Value, error) {
func (t *Object) Get(_ context.Context, key Value) (Value, error) {
val, found := t.data[key.String()]
if found {
@@ -331,8 +319,8 @@ func (t *hashMap) Get(_ context.Context, key Value) (Value, error) {
return None, nil
}
func (t *hashMap) Set(_ context.Context, key Value, value Value) error {
if value != nil {
func (t *Object) Set(_ context.Context, key Value, value Value) error {
if value == nil {
value = None
}
@@ -341,19 +329,19 @@ func (t *hashMap) Set(_ context.Context, key Value, value Value) error {
return nil
}
func (t *hashMap) Remove(_ context.Context, key Value) error {
func (t *Object) Remove(_ context.Context, key Value) error {
delete(t.data, key.String())
return nil
}
func (t *hashMap) Clear(_ context.Context) error {
func (t *Object) Clear(_ context.Context) error {
t.data = make(map[string]Value)
return nil
}
func (t *hashMap) Iterate(_ context.Context) (Iterator, error) {
func (t *Object) Iterate(_ context.Context) (Iterator, error) {
// TODO: implement channel based iterator
return NewObjectIterator(t), nil
}

View File

@@ -10,7 +10,7 @@ type ObjectIterator struct {
pos int
}
func NewObjectIterator(obj *hashMap) Iterator {
func NewObjectIterator(obj *Object) Iterator {
iter := &ObjectIterator{data: obj.data, keys: make([]string, len(obj.data))}
i := 0

View File

@@ -361,7 +361,7 @@ func TestObject(t *testing.T) {
core.NewObjectProperty("two", NewInt(2)),
)
clone := obj.Clone().(*core.hashMap)
clone := obj.Clone().(*core.Object)
So(obj.Compare(clone), ShouldEqual, 0)
})
@@ -372,7 +372,7 @@ func TestObject(t *testing.T) {
core.NewObjectProperty("two", NewInt(2)),
)
clone := obj.Clone().(*core.hashMap)
clone := obj.Clone().(*core.Object)
obj.Remove(NewString("one"))
@@ -386,7 +386,7 @@ func TestObject(t *testing.T) {
),
)
clone := obj.Clone().(*core.hashMap)
clone := obj.Clone().(*core.Object)
nestedInObj, _ := obj.Get(NewString("arr"))
nestedInObjArr := nestedInObj.(*Array)

View File

@@ -95,18 +95,18 @@ func (s String) Copy() Value {
return s
}
func (s String) Compare(_ context.Context, other Value) (int64, error) {
func (s String) Compare(other Value) int64 {
otherString, ok := other.(String)
if !ok {
return CompareTypes(s, other), nil
return CompareTypes(s, other)
}
return int64(strings.Compare(string(s), otherString.Unwrap().(string))), nil
return int64(strings.Compare(string(s), otherString.Unwrap().(string)))
}
func (s String) Length(_ context.Context) (int, error) {
return len([]rune(s)), nil
func (s String) Length(_ context.Context) (Int, error) {
return Int(len([]rune(s))), nil
}
func (s String) Contains(other String) Boolean {

View File

@@ -1,5 +1,7 @@
package core
import "reflect"
const (
TypeNone = "none"
TypeBoolean = "boolean"
@@ -11,6 +13,10 @@ const (
TypeSet = "set"
TypeMap = "map"
TypeBinary = "binary"
// Create subtypes for less specific types like interfaces
TypeIterable = "iterable"
TypeIterator = "iterator"
TypeMeasurable = "measurable"
)
func typeRank(value Value) int64 {
@@ -42,6 +48,41 @@ func typeRank(value Value) int64 {
}
}
func Reflect(input Value) string {
if input == None || input == nil {
return TypeNone
}
switch input.(type) {
case Boolean:
return TypeBoolean
case Int:
return TypeInt
case Float:
return TypeFloat
case String:
return TypeString
case DateTime:
return TypeDateTime
case List:
return TypeList
case Map:
return TypeMap
case Set:
return TypeSet
case Binary:
return TypeBinary
case Iterable:
return TypeIterable
case Iterator:
return TypeIterator
case Measurable:
return TypeMeasurable
default:
return reflect.TypeOf(input).String()
}
}
func CompareTypes(a, b Value) int64 {
aRank := typeRank(a)
bRank := typeRank(b)

View File

@@ -2,6 +2,10 @@ package runtime
import "github.com/pkg/errors"
var (
ErrMissedParam = errors.New("missed parameter")
)
type (
SourceErrorDetail struct {
error

View File

@@ -7,7 +7,6 @@ import (
"github.com/wI2L/jettison"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Boxed represents an arbitrary Value that can be boxed as a runtime Value.
@@ -34,7 +33,7 @@ func (b *Boxed) Unwrap() any {
func (b *Boxed) Hash() uint64 {
h := fnv.New64a()
h.Write([]byte(types.Boxed.String()))
h.Write([]byte("boxed"))
h.Write([]byte(":"))
h.Write([]byte(fmt.Sprintf("%v", b.Value)))

View File

@@ -7,7 +7,7 @@ import (
type DataSet struct {
hashmap map[uint64]bool
values *core.arrayList
values core.List
}
func NewDataSet(distinct bool) *DataSet {
@@ -23,15 +23,17 @@ func NewDataSet(distinct bool) *DataSet {
}
}
func (ds *DataSet) Swap(i, j int) {
ds.values.Swap(i, j)
func (ds *DataSet) Swap(ctx context.Context, i, j core.Int) {
ds.values.Swap(ctx, i, j)
}
func (ds *DataSet) Get(idx int) core.Value {
return ds.values.Get(idx)
func (ds *DataSet) Get(ctx context.Context, idx core.Int) core.Value {
val, _ := ds.values.Get(ctx, idx)
return val
}
func (ds *DataSet) Push(item core.Value) {
func (ds *DataSet) Push(ctx context.Context, item core.Value) {
if ds.hashmap != nil {
hash := item.Hash()
@@ -44,23 +46,23 @@ func (ds *DataSet) Push(item core.Value) {
ds.hashmap[hash] = true
}
ds.values.Push(item)
_ = ds.values.Add(ctx, item)
}
func (ds *DataSet) Iterate(ctx context.Context) (core.Iterator, error) {
return ds.values.Iterate(ctx)
}
func (ds *DataSet) Length() int {
return ds.values.Length()
func (ds *DataSet) Length(ctx context.Context) (core.Int, error) {
return ds.values.Length(ctx)
}
func (ds *DataSet) ToArray() *core.arrayList {
func (ds *DataSet) ToList() core.List {
return ds.values
}
func (ds *DataSet) String() string {
return "[DataSet]"
return "DataSet"
}
func (ds *DataSet) Unwrap() interface{} {

View File

@@ -1,10 +1,70 @@
package internal
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"go/types"
"strings"
)
func ToNumberOnly(ctx context.Context, input core.Value) core.Value {
switch value := input.(type) {
case core.Int, core.Float:
return value
case core.String:
if strings.Contains(value.String(), ".") {
if val, err := core.ToFloat(ctx, value); err == nil {
return val
}
return core.ZeroFloat
}
if val, err := core.ToInt(ctx, value); err == nil {
return val
}
return core.ZeroFloat
case core.Iterable:
iterator, err := value.Iterate(ctx)
if err != nil {
return core.ZeroInt
}
i := core.ZeroInt
f := core.ZeroFloat
for hasNext, err := iterator.HasNext(ctx); hasNext && err == nil; {
val, _, err := iterator.Next(ctx)
if err != nil {
continue
}
out := ToNumberOnly(ctx, val)
switch item := out.(type) {
case core.Int:
i += item
case core.Float:
f += item
}
}
if f == 0 {
return i
}
return core.Float(i) + f
default:
if val, err := core.ToFloat(ctx, value); err == nil {
return val
}
return core.ZeroInt
}
}
func ToRegexp(input core.Value) (*Regexp, error) {
switch r := input.(type) {
case *Regexp:
@@ -12,6 +72,6 @@ func ToRegexp(input core.Value) (*Regexp, error) {
case core.String:
return NewRegexp(r)
default:
return nil, TypeError(input, types.String, types.Regexp)
return nil, core.TypeError(input, core.TypeString, "regexp")
}
}

View File

@@ -13,6 +13,8 @@ type Iterator struct {
key core.Value
}
var NoopIter = NewIterator(&noopIter{})
func NewIterator(src core.Iterator) *Iterator {
return &Iterator{src, core.None, core.None}
}

View File

@@ -2,26 +2,15 @@ package internal
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
)
type noopIter struct{}
var NoopIter = &noopIter{}
func (it *noopIter) HasNext(ctx context.Context) (bool, error) {
func (n noopIter) HasNext(_ context.Context) (bool, error) {
return false, nil
}
func (it *noopIter) Next(_ context.Context) error {
return nil
}
func (it *noopIter) Value() core.Value {
return core.None
}
func (it *noopIter) Key() core.Value {
return core.None
func (n noopIter) Next(_ context.Context) (value core.Value, key core.Value, err error) {
return core.None, core.None, nil
}

View File

@@ -1,13 +1,39 @@
package internal
import (
"context"
"github.com/gobwas/glob"
"github.com/pkg/errors"
"strings"
"github.com/MontFerret/ferret/pkg/runtime/core"
)
func Add(inputL, inputR core.Value) core.Value {
func Contains(ctx context.Context, input core.Value, value core.Value) core.Boolean {
switch val := input.(type) {
case core.List:
contains, err := val.Contains(ctx, value)
if err != nil {
return core.False
}
return contains
case core.Map:
containsValue, err := val.ContainsValue(ctx, value)
if err != nil {
return core.False
}
return containsValue
case core.String:
return core.Boolean(strings.Contains(val.String(), value.String()))
default:
return false
}
}
func Add(ctx context.Context, inputL, inputR core.Value) core.Value {
left := core.ToNumberOrString(inputL)
switch leftVal := left.(type) {
@@ -52,21 +78,21 @@ func addLeftString(str core.String, input core.Value) core.Value {
return core.String(str.String() + input.String())
}
func Subtract(inputL, inputR core.Value) core.Value {
left := core.ToNumberOnly(inputL)
func Subtract(ctx context.Context, inputL, inputR core.Value) core.Value {
left := ToNumberOnly(ctx, inputL)
switch leftVal := left.(type) {
case core.Int:
return subtractLeftInt(leftVal, inputR)
return subtractLeftInt(ctx, leftVal, inputR)
case core.Float:
return subtractLeftFloat(leftVal, inputR)
return subtractLeftFloat(ctx, leftVal, inputR)
default:
return core.ZeroInt
}
}
func subtractLeftInt(integer core.Int, input core.Value) core.Value {
right := core.ToNumberOnly(input)
func subtractLeftInt(ctx context.Context, integer core.Int, input core.Value) core.Value {
right := ToNumberOnly(ctx, input)
switch rightVal := right.(type) {
case core.Int:
@@ -78,8 +104,8 @@ func subtractLeftInt(integer core.Int, input core.Value) core.Value {
}
}
func subtractLeftFloat(float core.Float, input core.Value) core.Value {
right := core.ToNumberOnly(input)
func subtractLeftFloat(ctx context.Context, float core.Float, input core.Value) core.Value {
right := ToNumberOnly(ctx, input)
switch rightVal := right.(type) {
case core.Int:
@@ -91,21 +117,21 @@ func subtractLeftFloat(float core.Float, input core.Value) core.Value {
}
}
func Multiply(inputL, inputR core.Value) core.Value {
left := core.ToNumberOnly(inputL)
func Multiply(ctx context.Context, inputL, inputR core.Value) core.Value {
left := ToNumberOnly(ctx, inputL)
switch leftVal := left.(type) {
case core.Int:
return multiplyLeftInt(leftVal, inputR)
return multiplyLeftInt(ctx, leftVal, inputR)
case core.Float:
return multiplyLeftFloat(leftVal, inputR)
return multiplyLeftFloat(ctx, leftVal, inputR)
default:
return core.ZeroInt
}
}
func multiplyLeftInt(integer core.Int, input core.Value) core.Value {
right := core.ToNumberOnly(input)
func multiplyLeftInt(ctx context.Context, integer core.Int, input core.Value) core.Value {
right := ToNumberOnly(ctx, input)
switch rightVal := right.(type) {
case core.Int:
@@ -117,8 +143,8 @@ func multiplyLeftInt(integer core.Int, input core.Value) core.Value {
}
}
func multiplyLeftFloat(float core.Float, input core.Value) core.Value {
right := core.ToNumberOnly(input)
func multiplyLeftFloat(ctx context.Context, float core.Float, input core.Value) core.Value {
right := ToNumberOnly(ctx, input)
switch rightVal := right.(type) {
case core.Int:
@@ -130,21 +156,21 @@ func multiplyLeftFloat(float core.Float, input core.Value) core.Value {
}
}
func Divide(inputL, inputR core.Value) core.Value {
left := core.ToNumberOnly(inputL)
func Divide(ctx context.Context, inputL, inputR core.Value) core.Value {
left := ToNumberOnly(ctx, inputL)
switch leftVal := left.(type) {
case core.Int:
return divideLeftInt(leftVal, inputR)
return divideLeftInt(ctx, leftVal, inputR)
case core.Float:
return divideLeftFloat(leftVal, inputR)
return divideLeftFloat(ctx, leftVal, inputR)
default:
return core.ZeroInt
}
}
func divideLeftInt(integer core.Int, input core.Value) core.Value {
right := core.ToNumberOnly(input)
func divideLeftInt(ctx context.Context, integer core.Int, input core.Value) core.Value {
right := ToNumberOnly(ctx, input)
switch rightVal := right.(type) {
case core.Int:
@@ -156,8 +182,8 @@ func divideLeftInt(integer core.Int, input core.Value) core.Value {
}
}
func divideLeftFloat(float core.Float, input core.Value) core.Value {
right := core.ToNumberOnly(input)
func divideLeftFloat(ctx context.Context, float core.Float, input core.Value) core.Value {
right := ToNumberOnly(ctx, input)
switch rightVal := right.(type) {
case core.Int:
@@ -169,15 +195,15 @@ func divideLeftFloat(float core.Float, input core.Value) core.Value {
}
}
func Modulus(inputL, inputR core.Value) core.Value {
left := core.ToInt(inputL)
right := core.ToInt(inputR)
func Modulus(ctx context.Context, inputL, inputR core.Value) core.Value {
left, _ := core.ToInt(ctx, inputL)
right, _ := core.ToInt(ctx, inputR)
return left % right
}
func Increment(input core.Value) core.Value {
left := core.ToNumberOnly(input)
func Increment(ctx context.Context, input core.Value) core.Value {
left := ToNumberOnly(ctx, input)
switch value := left.(type) {
case core.Int:
@@ -189,8 +215,8 @@ func Increment(input core.Value) core.Value {
}
}
func Decrement(input core.Value) core.Value {
left := core.ToNumberOnly(input)
func Decrement(ctx context.Context, input core.Value) core.Value {
left := ToNumberOnly(ctx, input)
switch value := left.(type) {
case core.Int:
@@ -202,9 +228,18 @@ func Decrement(input core.Value) core.Value {
}
}
func Range(left, right core.Value) (core.Value, error) {
start := core.ToInt(left)
end := core.ToInt(right)
func ToRange(ctx context.Context, left, right core.Value) (core.Value, error) {
start, err := core.ToInt(ctx, left)
if err != nil {
return core.ZeroInt, err
}
end, err := core.ToInt(ctx, right)
if err != nil {
return core.ZeroInt, err
}
return NewRange(int64(start), int64(end)), nil
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/wI2L/jettison"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
type Range struct {
@@ -40,7 +39,7 @@ func (r *Range) Unwrap() interface{} {
func (r *Range) Hash() uint64 {
h := fnv.New64a()
h.Write([]byte(types.Range.String()))
h.Write([]byte("range"))
h.Write([]byte(":"))
startMultiplier := 1
@@ -93,7 +92,7 @@ func (r *Range) Compare(_ context.Context, other core.Value) (int64, error) {
otherRange, ok := other.(*Range)
if !ok {
return types.Compare(types.Range, core.Reflect(other)), nil
return core.CompareTypes(r, other), nil
}
if r.start == otherRange.start && r.end == otherRange.end {

View File

@@ -2,7 +2,6 @@ package internal
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
"hash/fnv"
"regexp"
"strings"
@@ -24,10 +23,6 @@ func NewRegexp(pattern core.String) (*Regexp, error) {
return (*Regexp)(r), nil
}
func (r *Regexp) Type() core.Type {
return types.Regexp
}
func (r *Regexp) MarshalJSON() ([]byte, error) {
return jettison.MarshalOpts(r.String(), jettison.NoHTMLEscaping())
}
@@ -43,7 +38,7 @@ func (r *Regexp) Unwrap() interface{} {
func (r *Regexp) Hash() uint64 {
h := fnv.New64a()
h.Write([]byte(types.Regexp.String()))
h.Write([]byte("regexp"))
h.Write([]byte(":"))
h.Write([]byte(r.String()))
@@ -65,7 +60,7 @@ func (r *Regexp) Compare(_ context.Context, other core.Value) (int64, error) {
otherRegexp, ok := other.(*Regexp)
if !ok {
return types.Compare(types.Regexp, core.Reflect(other)), nil
return core.CompareTypes(r, other), nil
}
return int64(strings.Compare(r.String(), otherRegexp.String())), nil

View File

@@ -7,17 +7,17 @@ import (
type (
Sequence struct {
data *core.arrayList
data core.List
}
sequenceIterator struct {
data *core.arrayList
length int
pos int
data core.List
length core.Int
pos core.Int
}
)
func NewSequence(data *core.arrayList) *Sequence {
func NewSequence(data core.List) *Sequence {
return &Sequence{data}
}
@@ -25,15 +25,28 @@ func (iter *sequenceIterator) HasNext(_ context.Context) (bool, error) {
return iter.length > iter.pos, nil
}
func (iter *sequenceIterator) Next(_ context.Context) (value core.Value, key core.Value, err error) {
func (iter *sequenceIterator) Next(ctx context.Context) (value core.Value, key core.Value, err error) {
iter.pos++
// TODO: Make it less ugly
return iter.data.Get(iter.pos - 1).(*KeyValuePair).Value, core.NewInt(iter.pos - 1), nil
val, err := iter.data.Get(ctx, iter.pos-1)
if err != nil {
return nil, nil, err
}
kv := val.(*KeyValuePair)
return kv.Value, iter.pos - 1, nil
}
func (s *Sequence) Iterate(_ context.Context) (core.Iterator, error) {
return &sequenceIterator{data: s.data, length: s.data.Length(), pos: 0}, nil
func (s *Sequence) Iterate(ctx context.Context) (core.Iterator, error) {
length, err := s.data.Length(ctx)
if err != nil {
return nil, err
}
return &sequenceIterator{data: s.data, length: length, pos: 0}, nil
}
func (s *Sequence) MarshalJSON() ([]byte, error) {

View File

@@ -2,7 +2,6 @@ package runtime
import (
"context"
"go/types"
"io"
"strings"
@@ -103,19 +102,19 @@ loop:
vm.pc = int(dst)
}
case OpAdd:
reg[dst] = internal.Add(reg[src1], reg[src2])
reg[dst] = internal.Add(ctx, reg[src1], reg[src2])
case OpSub:
reg[dst] = internal.Subtract(reg[src1], reg[src2])
reg[dst] = internal.Subtract(ctx, reg[src1], reg[src2])
case OpMulti:
reg[dst] = internal.Multiply(reg[src1], reg[src2])
reg[dst] = internal.Multiply(ctx, reg[src1], reg[src2])
case OpDiv:
reg[dst] = internal.Divide(reg[src1], reg[src2])
reg[dst] = internal.Divide(ctx, reg[src1], reg[src2])
case OpMod:
reg[dst] = internal.Modulus(reg[src1], reg[src2])
reg[dst] = internal.Modulus(ctx, reg[src1], reg[src2])
case OpIncr:
reg[dst] = internal.Increment(reg[dst])
reg[dst] = internal.Increment(ctx, reg[dst])
case OpDecr:
reg[dst] = internal.Decrement(reg[dst])
reg[dst] = internal.Decrement(ctx, reg[dst])
case OpCastBool:
reg[dst] = core.ToBoolean(reg[src1])
case OpNegate:
@@ -141,9 +140,9 @@ loop:
case OpLte:
reg[dst] = core.Boolean(core.CompareValues(reg[src1], reg[src2]) <= 0)
case OpIn:
reg[dst] = core.Contains(reg[src2], reg[src1])
reg[dst] = internal.Contains(ctx, reg[src2], reg[src1])
case OpNotIn:
reg[dst] = !core.Contains(reg[src2], reg[src1])
reg[dst] = !internal.Contains(ctx, reg[src2], reg[src1])
case OpLike:
res, err := internal.Like(reg[src1], reg[src2])
@@ -162,7 +161,7 @@ loop:
}
case OpRegexpPositive:
// TODO: Add caching to avoid recompilation
r, err := core.ToRegexp(reg[src2])
r, err := internal.ToRegexp(reg[src2])
if err == nil {
reg[dst] = r.Match(reg[src1])
@@ -173,7 +172,7 @@ loop:
}
case OpRegexpNegative:
// TODO: Add caching to avoid recompilation
r, err := core.ToRegexp(reg[src2])
r, err := internal.ToRegexp(reg[src2])
if err == nil {
reg[dst] = !r.Match(reg[src1])
@@ -237,15 +236,17 @@ loop:
}
default:
if op != OpLoadPropertyOptional {
return nil, core.TypeError(src, types.Object, types.Keyed)
return nil, core.TypeError(src, core.TypeMap)
}
reg[dst] = core.None
}
case core.Float, core.Int:
// TODO: Optimize this. Avoid extra type conversion
idx, _ := core.ToInt(ctx, getter)
switch src := val.(type) {
case core.Indexed:
out, err := src.Get(ctx, int(core.ToInt(getter)))
out, err := src.Get(ctx, idx)
if err == nil {
reg[dst] = out
@@ -255,12 +256,10 @@ loop:
return nil, err
}
case *internal.DataSet:
idx := core.ToInt(getter)
reg[dst] = src.Get(int(idx))
reg[dst] = src.Get(ctx, idx)
default:
if op != OpLoadPropertyOptional {
return nil, core.TypeError(src, types.Array, types.Indexed)
return nil, core.TypeError(src, core.TypeList)
}
reg[dst] = core.None
@@ -314,20 +313,20 @@ loop:
}
}
reg[dst] = core.NewInt(length)
reg[dst] = length
} else if _, catch := tryCatch(vm.pc); catch {
reg[dst] = core.ZeroInt
} else {
return core.None, core.TypeError(reg[src1],
types.String,
types.Array,
types.Object,
types.Binary,
types.Measurable,
core.TypeString,
core.TypeList,
core.TypeMap,
core.TypeBinary,
core.TypeMeasurable,
)
}
case OpType:
reg[dst] = core.String(core.Reflect(reg[src1]).Name())
reg[dst] = core.String(core.Reflect(reg[src1]))
case OpClose:
val, ok := reg[dst].(io.Closer)
reg[dst] = core.None
@@ -342,7 +341,7 @@ loop:
}
}
case OpRange:
res, err := internal.Range(reg[src1], reg[src2])
res, err := internal.ToRange(ctx, reg[src1], reg[src2])
if err == nil {
reg[dst] = res
@@ -353,7 +352,7 @@ loop:
reg[dst] = internal.NewDataSet(src1 == 1)
case OpLoopEnd:
ds := reg[src1].(*internal.DataSet)
reg[dst] = ds.ToArray()
reg[dst] = ds.ToList()
case OpForLoopPrep:
input := reg[src1]
@@ -369,9 +368,9 @@ loop:
default:
if _, catch := tryCatch(vm.pc); catch {
// Fall back to an empty iterator
reg[dst] = internal.NewBoxedValue(internal.NoopIter)
reg[dst] = internal.NoopIter
} else {
return nil, core.TypeError(src, types.Iterable)
return nil, core.TypeError(src, core.TypeIterable)
}
}
case OpForLoopNext:
@@ -401,7 +400,7 @@ loop:
cond := core.ToBoolean(reg[src1])
if cond {
reg[dst] = internal.Increment(reg[dst])
reg[dst] = internal.Increment(ctx, reg[dst])
} else {
vm.pc = int(src2)
}
@@ -409,17 +408,17 @@ loop:
reg[dst] = reg[src1]
case OpLoopPush:
ds := reg[dst].(*internal.DataSet)
ds.Push(reg[src1])
ds.Push(ctx, reg[src1])
case OpLoopPushIter:
ds := reg[dst].(*internal.DataSet)
iterator := reg[src1].(*internal.Iterator)
ds.Push(&internal.KeyValuePair{
ds.Push(ctx, &internal.KeyValuePair{
Key: iterator.Key(),
Value: iterator.Value(),
})
case OpLoopSequence:
ds := reg[src1].(*internal.DataSet)
reg[dst] = internal.NewSequence(ds.ToArray())
reg[dst] = internal.NewSequence(ds.ToList())
case OpSortPrep:
reg[dst] = internal.NewStack(3)
case OpSortPush:
@@ -436,9 +435,9 @@ loop:
reg[dst] = pair.Key
case OpSortSwap:
ds := reg[dst].(*internal.DataSet)
i := core.ToInt(reg[src1])
j := core.ToInt(reg[src2])
ds.Swap(int(i), int(j))
i, _ := core.ToInt(ctx, reg[src1])
j, _ := core.ToInt(ctx, reg[src2])
ds.Swap(ctx, i, j)
case OpGroupPrep:
reg[dst] = internal.NewCollector()
case OpGroupAdd:

View File

@@ -3,7 +3,6 @@ package types
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/internal"
)
// TO_ARRAY takes an input value of any type and convert it into an array value.
@@ -20,5 +19,5 @@ func ToArray(ctx context.Context, args ...core.Value) (core.Value, error) {
return core.None, err
}
return internal.ToArray(ctx, args[0]), nil
return core.ToList(ctx, args[0]), nil
}

View File

@@ -2,7 +2,6 @@ package utils
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/internal"
"time"
"github.com/MontFerret/ferret/pkg/runtime/core"
@@ -17,7 +16,7 @@ func Wait(ctx context.Context, args ...core.Value) (core.Value, error) {
return core.None, nil
}
arg := internal.ToInt(args[0])
arg := core.ToIntSafe(ctx, args[0])
timer := time.NewTimer(time.Millisecond * time.Duration(arg))
select {