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:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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()
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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}
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
//})
|
||||
|
@@ -80,7 +80,7 @@ func AssertMap(input Value) error {
|
||||
if !ok {
|
||||
return TypeError(
|
||||
input,
|
||||
"map",
|
||||
TypeMap,
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -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()))
|
||||
}
|
||||
|
@@ -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))
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
|
@@ -2,6 +2,10 @@ package runtime
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
var (
|
||||
ErrMissedParam = errors.New("missed parameter")
|
||||
)
|
||||
|
||||
type (
|
||||
SourceErrorDetail struct {
|
||||
error
|
||||
|
@@ -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)))
|
||||
|
||||
|
@@ -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{} {
|
||||
|
@@ -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")
|
||||
}
|
||||
}
|
||||
|
@@ -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}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user