mirror of
https://github.com/MontFerret/ferret.git
synced 2025-03-03 15:02:32 +02:00
Move value specific Iterable and Iterator interfaces into core module (#233)
* Move value specific Iterable and Iterator interfaces into core module * Update Makefile Reverted test command * Update collection.go * Fixed wrong iterator usage * Updated use of switch statements
This commit is contained in:
parent
1af8b37a0f
commit
f8e061cc80
2
Makefile
2
Makefile
@ -64,4 +64,4 @@ else
|
||||
git tag -a v$(RELEASE_VERSION) -m "New $(RELEASE_VERSION) version" && \
|
||||
git push origin v$(RELEASE_VERSION) && \
|
||||
goreleaser
|
||||
endif
|
||||
endif
|
||||
|
@ -78,11 +78,11 @@ func (flags Flags) List() []string {
|
||||
continue
|
||||
}
|
||||
|
||||
switch val.(type) {
|
||||
switch v := val.(type) {
|
||||
case int:
|
||||
arg = fmt.Sprintf("--%s=%d", arg, val.(int))
|
||||
arg = fmt.Sprintf("--%s=%d", arg, v)
|
||||
case string:
|
||||
arg = fmt.Sprintf("--%s=%s", arg, val.(string))
|
||||
arg = fmt.Sprintf("--%s=%s", arg, v)
|
||||
default:
|
||||
arg = fmt.Sprintf("--%s", arg)
|
||||
}
|
||||
|
@ -1430,37 +1430,37 @@ func (v *visitor) visit(node antlr.Tree, scope *scope) (core.Expression, error)
|
||||
var out core.Expression
|
||||
var err error
|
||||
|
||||
switch node.(type) {
|
||||
switch ctx := node.(type) {
|
||||
case *fql.BodyContext:
|
||||
out, err = v.doVisitBody(node.(*fql.BodyContext), scope)
|
||||
out, err = v.doVisitBody(ctx, scope)
|
||||
case *fql.ExpressionContext:
|
||||
out, err = v.doVisitExpression(node.(*fql.ExpressionContext), scope)
|
||||
out, err = v.doVisitExpression(ctx, scope)
|
||||
case *fql.ForExpressionContext:
|
||||
out, err = v.doVisitForExpression(node.(*fql.ForExpressionContext), scope)
|
||||
out, err = v.doVisitForExpression(ctx, scope)
|
||||
case *fql.ReturnExpressionContext:
|
||||
out, err = v.doVisitReturnExpression(node.(*fql.ReturnExpressionContext), scope)
|
||||
out, err = v.doVisitReturnExpression(ctx, scope)
|
||||
case *fql.ArrayLiteralContext:
|
||||
out, err = v.doVisitArrayLiteral(node.(*fql.ArrayLiteralContext), scope)
|
||||
out, err = v.doVisitArrayLiteral(ctx, scope)
|
||||
case *fql.ObjectLiteralContext:
|
||||
out, err = v.doVisitObjectLiteral(node.(*fql.ObjectLiteralContext), scope)
|
||||
out, err = v.doVisitObjectLiteral(ctx, scope)
|
||||
case *fql.StringLiteralContext:
|
||||
out, err = v.doVisitStringLiteral(node.(*fql.StringLiteralContext))
|
||||
out, err = v.doVisitStringLiteral(ctx)
|
||||
case *fql.IntegerLiteralContext:
|
||||
out, err = v.doVisitIntegerLiteral(node.(*fql.IntegerLiteralContext))
|
||||
out, err = v.doVisitIntegerLiteral(ctx)
|
||||
case *fql.FloatLiteralContext:
|
||||
out, err = v.doVisitFloatLiteral(node.(*fql.FloatLiteralContext))
|
||||
out, err = v.doVisitFloatLiteral(ctx)
|
||||
case *fql.BooleanLiteralContext:
|
||||
out, err = v.doVisitBooleanLiteral(node.(*fql.BooleanLiteralContext))
|
||||
out, err = v.doVisitBooleanLiteral(ctx)
|
||||
case *fql.NoneLiteralContext:
|
||||
out, err = v.doVisitNoneLiteral(node.(*fql.NoneLiteralContext))
|
||||
out, err = v.doVisitNoneLiteral(ctx)
|
||||
case *fql.VariableContext:
|
||||
out, err = v.doVisitVariable(node.(*fql.VariableContext), scope)
|
||||
out, err = v.doVisitVariable(ctx, scope)
|
||||
case *fql.VariableDeclarationContext:
|
||||
out, err = v.doVisitVariableDeclaration(node.(*fql.VariableDeclarationContext), scope)
|
||||
out, err = v.doVisitVariableDeclaration(ctx, scope)
|
||||
case *fql.FunctionCallExpressionContext:
|
||||
out, err = v.doVisitFunctionCallExpression(node.(*fql.FunctionCallExpressionContext), scope)
|
||||
out, err = v.doVisitFunctionCallExpression(ctx, scope)
|
||||
case *fql.ParamContext:
|
||||
out, err = v.doVisitParamContext(node.(*fql.ParamContext), scope)
|
||||
out, err = v.doVisitParamContext(ctx, scope)
|
||||
default:
|
||||
err = v.unexpectedToken(node)
|
||||
}
|
||||
|
@ -7,49 +7,42 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
Collection interface {
|
||||
core.Value
|
||||
// Measurable represents an interface of a value that can has length.
|
||||
Measurable interface {
|
||||
Length() values.Int
|
||||
}
|
||||
|
||||
IndexedCollection interface {
|
||||
Collection
|
||||
core.Value
|
||||
Measurable
|
||||
Get(idx values.Int) core.Value
|
||||
Set(idx values.Int, value core.Value) error
|
||||
}
|
||||
|
||||
KeyedCollection interface {
|
||||
Collection
|
||||
core.Value
|
||||
Measurable
|
||||
Keys() []string
|
||||
Get(key values.String) (core.Value, values.Boolean)
|
||||
Set(key values.String, value core.Value)
|
||||
}
|
||||
|
||||
IterableCollection interface {
|
||||
core.Value
|
||||
Iterate(ctx context.Context) (CollectionIterator, error)
|
||||
}
|
||||
|
||||
CollectionIterator interface {
|
||||
Next(ctx context.Context) (value core.Value, key core.Value, err error)
|
||||
}
|
||||
|
||||
collectionIteratorWrapper struct {
|
||||
coreIterator struct {
|
||||
valVar string
|
||||
keyVar string
|
||||
values CollectionIterator
|
||||
values core.Iterator
|
||||
}
|
||||
)
|
||||
|
||||
func NewCollectionIterator(
|
||||
func NewCoreIterator(
|
||||
valVar,
|
||||
keyVar string,
|
||||
values CollectionIterator,
|
||||
values core.Iterator,
|
||||
) (Iterator, error) {
|
||||
return &collectionIteratorWrapper{valVar, keyVar, values}, nil
|
||||
return &coreIterator{valVar, keyVar, values}, nil
|
||||
}
|
||||
|
||||
func (iterator *collectionIteratorWrapper) Next(ctx context.Context, scope *core.Scope) (*core.Scope, error) {
|
||||
func (iterator *coreIterator) Next(ctx context.Context, scope *core.Scope) (*core.Scope, error) {
|
||||
val, key, err := iterator.values.Next(ctx)
|
||||
|
||||
if err != nil {
|
||||
|
@ -18,6 +18,17 @@ type (
|
||||
Copy() Value
|
||||
}
|
||||
|
||||
// Iterable represents an interface of a value that can be iterated by using an iterator.
|
||||
Iterable interface {
|
||||
Iterate(ctx context.Context) (Iterator, error)
|
||||
}
|
||||
|
||||
// Iterator represents an interface of a value iterator.
|
||||
// When iterator is exhausted it must return None as a value.
|
||||
Iterator interface {
|
||||
Next(ctx context.Context) (value Value, key Value, err error)
|
||||
}
|
||||
|
||||
// Getter represents an interface of
|
||||
// complex types that needs to be used to read values by path.
|
||||
// The interface is created to let user-defined types be used in dot notation data access.
|
||||
|
@ -54,20 +54,19 @@ func (ds *DataSource) Iterate(ctx context.Context, scope *core.Scope) (collectio
|
||||
return collections.NewHTMLNodeIterator(ds.valVariable, ds.keyVariable, data.(values.HTMLNode))
|
||||
default:
|
||||
// fallback to user defined types
|
||||
switch data.(type) {
|
||||
case collections.IterableCollection:
|
||||
collection := data.(collections.IterableCollection)
|
||||
switch collection := data.(type) {
|
||||
case core.Iterable:
|
||||
iterator, err := collection.Iterate(ctx)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return collections.NewCollectionIterator(ds.valVariable, ds.keyVariable, iterator)
|
||||
return collections.NewCoreIterator(ds.valVariable, ds.keyVariable, iterator)
|
||||
case collections.KeyedCollection:
|
||||
return collections.NewIndexedIterator(ds.valVariable, ds.keyVariable, data.(collections.IndexedCollection))
|
||||
return collections.NewKeyedIterator(ds.valVariable, ds.keyVariable, collection)
|
||||
case collections.IndexedCollection:
|
||||
return collections.NewKeyedIterator(ds.valVariable, ds.keyVariable, data.(collections.KeyedCollection))
|
||||
return collections.NewIndexedIterator(ds.valVariable, ds.keyVariable, collection)
|
||||
default:
|
||||
return nil, core.TypeError(
|
||||
data.Type(),
|
||||
@ -75,6 +74,7 @@ func (ds *DataSource) Iterate(ctx context.Context, scope *core.Scope) (collectio
|
||||
types.Object,
|
||||
types.HTMLDocument,
|
||||
types.HTMLElement,
|
||||
core.NewType("Iterable"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ package expressions_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/expressions"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"testing"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/collections"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/expressions"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
@ -51,7 +51,7 @@ func (c *testIterableCollection) Hash() uint64 {
|
||||
func (c *testIterableCollection) Copy() core.Value {
|
||||
return c
|
||||
}
|
||||
func (c *testIterableCollection) Iterate(ctx context.Context) (collections.CollectionIterator, error) {
|
||||
func (c *testIterableCollection) Iterate(ctx context.Context) (core.Iterator, error) {
|
||||
return &testCollectionIterator{c.values, -1}, nil
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,9 @@ func ParseDateTime(input interface{}) (DateTime, error) {
|
||||
}
|
||||
|
||||
func ParseDateTimeWith(input interface{}, layout string) (DateTime, error) {
|
||||
switch input.(type) {
|
||||
switch value := input.(type) {
|
||||
case string:
|
||||
t, err := time.Parse(layout, input.(string))
|
||||
t, err := time.Parse(layout, value)
|
||||
|
||||
if err != nil {
|
||||
return DateTime{time.Now()}, err
|
||||
|
@ -206,44 +206,42 @@ func SetIn(ctx context.Context, to core.Value, byPath []core.Value, value core.V
|
||||
}
|
||||
|
||||
func Parse(input interface{}) core.Value {
|
||||
switch input.(type) {
|
||||
switch value := input.(type) {
|
||||
case bool:
|
||||
return NewBoolean(input.(bool))
|
||||
return NewBoolean(value)
|
||||
case string:
|
||||
return NewString(input.(string))
|
||||
return NewString(value)
|
||||
case int:
|
||||
return NewInt(input.(int))
|
||||
return NewInt(value)
|
||||
case float64:
|
||||
return NewFloat(input.(float64))
|
||||
return NewFloat(value)
|
||||
case float32:
|
||||
return NewFloat(float64(input.(float32)))
|
||||
return NewFloat(float64(value))
|
||||
case time.Time:
|
||||
return NewDateTime(input.(time.Time))
|
||||
return NewDateTime(value)
|
||||
case []interface{}:
|
||||
input := input.([]interface{})
|
||||
arr := NewArray(len(input))
|
||||
arr := NewArray(len(value))
|
||||
|
||||
for _, el := range input {
|
||||
for _, el := range value {
|
||||
arr.Push(Parse(el))
|
||||
}
|
||||
|
||||
return arr
|
||||
case map[string]interface{}:
|
||||
input := input.(map[string]interface{})
|
||||
obj := NewObject()
|
||||
|
||||
for key, el := range input {
|
||||
for key, el := range value {
|
||||
obj.Set(NewString(key), Parse(el))
|
||||
}
|
||||
|
||||
return obj
|
||||
case []byte:
|
||||
return NewBinary(input.([]byte))
|
||||
return NewBinary(value)
|
||||
case nil:
|
||||
return None
|
||||
default:
|
||||
v := reflect.ValueOf(input)
|
||||
t := reflect.TypeOf(input)
|
||||
v := reflect.ValueOf(value)
|
||||
t := reflect.TypeOf(value)
|
||||
kind := t.Kind()
|
||||
|
||||
if kind == reflect.Slice || kind == reflect.Array {
|
||||
@ -251,8 +249,8 @@ func Parse(input interface{}) core.Value {
|
||||
arr := NewArray(size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
value := v.Index(i)
|
||||
arr.Push(Parse(value.Interface()))
|
||||
curVal := v.Index(i)
|
||||
arr.Push(Parse(curVal.Interface()))
|
||||
}
|
||||
|
||||
return arr
|
||||
@ -264,9 +262,9 @@ func Parse(input interface{}) core.Value {
|
||||
|
||||
for _, k := range keys {
|
||||
key := Parse(k.Interface())
|
||||
value := v.MapIndex(k)
|
||||
curVal := v.MapIndex(k)
|
||||
|
||||
obj.Set(NewString(key.String()), Parse(value.Interface()))
|
||||
obj.Set(NewString(key.String()), Parse(curVal.Interface()))
|
||||
}
|
||||
|
||||
return obj
|
||||
@ -278,9 +276,9 @@ func Parse(input interface{}) core.Value {
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
field := t.Field(i)
|
||||
value := v.Field(i)
|
||||
fieldValue := v.Field(i)
|
||||
|
||||
obj.Set(NewString(field.Name), Parse(value.Interface()))
|
||||
obj.Set(NewString(field.Name), Parse(fieldValue.Interface()))
|
||||
}
|
||||
|
||||
return obj
|
||||
|
@ -23,7 +23,7 @@ func TestAppend(t *testing.T) {
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(out, ShouldNotEqual, arr)
|
||||
So(out.(collections.Collection).Length(), ShouldBeGreaterThan, arr.Length())
|
||||
So(out.(collections.Measurable).Length(), ShouldBeGreaterThan, arr.Length())
|
||||
})
|
||||
|
||||
Convey("Should ignore non-unique items", t, func() {
|
||||
@ -39,12 +39,12 @@ func TestAppend(t *testing.T) {
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(out, ShouldNotEqual, arr)
|
||||
So(out.(collections.Collection).Length(), ShouldEqual, arr.Length())
|
||||
So(out.(collections.Measurable).Length(), ShouldEqual, arr.Length())
|
||||
|
||||
out2, err := arrays.Append(context.Background(), arr, values.NewInt(6), values.True)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(out2, ShouldNotEqual, arr)
|
||||
So(out2.(collections.Collection).Length(), ShouldBeGreaterThan, arr.Length())
|
||||
So(out2.(collections.Measurable).Length(), ShouldBeGreaterThan, arr.Length())
|
||||
})
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ func Length(_ context.Context, inputs ...core.Value) (core.Value, error) {
|
||||
|
||||
value := inputs[0]
|
||||
|
||||
c, ok := value.(collections.Collection)
|
||||
c, ok := value.(collections.Measurable)
|
||||
|
||||
if !ok {
|
||||
return values.None, core.TypeError(value.Type(),
|
||||
@ -28,7 +28,7 @@ func Length(_ context.Context, inputs ...core.Value) (core.Value, error) {
|
||||
types.HTMLElement,
|
||||
types.HTMLDocument,
|
||||
types.Binary,
|
||||
core.NewType("Collection"),
|
||||
core.NewType("Measurable"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package html
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/collections"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
@ -81,7 +80,7 @@ func (p *Paging) Copy() core.Value {
|
||||
return values.None
|
||||
}
|
||||
|
||||
func (p *Paging) Iterate(_ context.Context) (collections.CollectionIterator, error) {
|
||||
func (p *Paging) Iterate(_ context.Context) (core.Iterator, error) {
|
||||
return &PagingIterator{p.document, p.selector, -1}, nil
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout := values.NewInt(defaultTimeout)
|
||||
|
||||
// lets figure out what is passed as 1st argument
|
||||
switch args[0].(type) {
|
||||
switch obj := args[0].(type) {
|
||||
case values.DHTMLDocument:
|
||||
// revalidate args with more accurate amount
|
||||
err := core.ValidateArgs(args, 3, 4)
|
||||
@ -57,12 +57,6 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
doc, ok := args[0].(values.DHTMLDocument)
|
||||
|
||||
if !ok {
|
||||
return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic)
|
||||
}
|
||||
|
||||
selector := args[1].(values.String)
|
||||
class := args[2].(values.String)
|
||||
|
||||
@ -76,14 +70,8 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[3].(values.Int)
|
||||
}
|
||||
|
||||
return values.None, doc.WaitForClass(selector, class, timeout)
|
||||
return values.None, obj.WaitForClass(selector, class, timeout)
|
||||
case values.DHTMLNode:
|
||||
el, ok := args[0].(values.DHTMLNode)
|
||||
|
||||
if !ok {
|
||||
return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic)
|
||||
}
|
||||
|
||||
class := args[1].(values.String)
|
||||
|
||||
if len(args) == 3 {
|
||||
@ -96,7 +84,7 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[2].(values.Int)
|
||||
}
|
||||
|
||||
return values.None, el.WaitForClass(class, timeout)
|
||||
return values.None, obj.WaitForClass(class, timeout)
|
||||
default:
|
||||
return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user