diff --git a/go.sum b/go.sum index 84dc6eb2..2eea0ac2 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc h1:N3zlSgxkefUH/ecsl37RWTkESTB026kmXzNly8TuZCI= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 083b6e3c..a4915366 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -16,7 +16,7 @@ type Compiler struct { func New(setters ...Option) *Compiler { c := &Compiler{} c.NamespaceContainer = newRootNamespace() - c.funcs = make(map[string]core.Function) + c.funcs = make(core.Functions) opts := &Options{} diff --git a/pkg/compiler/namespace.go b/pkg/compiler/namespace.go index bae47a38..85121532 100644 --- a/pkg/compiler/namespace.go +++ b/pkg/compiler/namespace.go @@ -1,10 +1,11 @@ package compiler import ( - "github.com/MontFerret/ferret/pkg/runtime/core" - "github.com/pkg/errors" "regexp" "strings" + + "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/pkg/errors" ) var fnNameValidation = regexp.MustCompile("^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)*$") @@ -34,7 +35,8 @@ func (nc *NamespaceContainer) Namespace(name string) core.Namespace { func (nc *NamespaceContainer) RegisterFunction(name string, fun core.Function) error { nsName := nc.makeFullName(name) - _, exists := nc.funcs[nsName] + + _, exists := nc.funcs.Get(nsName) if exists { return errors.Errorf("function already exists: %s", name) @@ -49,13 +51,13 @@ func (nc *NamespaceContainer) RegisterFunction(name string, fun core.Function) e return errors.Errorf("invalid function or namespace name: %s", nsName) } - nc.funcs[strings.ToUpper(nsName)] = fun + nc.funcs.Set(nsName, fun) return nil } func (nc *NamespaceContainer) RemoveFunction(name string) { - delete(nc.funcs, strings.ToUpper(nc.makeFullName(name))) + nc.funcs.Unset(nc.makeFullName(name)) } func (nc *NamespaceContainer) RegisterFunctions(funcs core.Functions) error { diff --git a/pkg/compiler/visitor.go b/pkg/compiler/visitor.go index dedd6cad..4764aeef 100644 --- a/pkg/compiler/visitor.go +++ b/pkg/compiler/visitor.go @@ -24,11 +24,11 @@ type ( visitor struct { *fql.BaseFqlParserVisitor src string - funcs map[string]core.Function + funcs core.Functions } ) -func newVisitor(src string, funcs map[string]core.Function) *visitor { +func newVisitor(src string, funcs core.Functions) *visitor { return &visitor{ &fql.BaseFqlParserVisitor{}, src, @@ -1104,7 +1104,7 @@ func (v *visitor) doVisitFunctionCallExpression(context *fql.FunctionCallExpress name += context.Identifier().GetText() - fun, exists := v.funcs[name] + fun, exists := v.funcs.Get(name) if !exists { return nil, core.Error(core.ErrNotFound, fmt.Sprintf("function: '%s'", name)) diff --git a/pkg/runtime/core/function.go b/pkg/runtime/core/function.go index 6c67a6ff..aa609332 100644 --- a/pkg/runtime/core/function.go +++ b/pkg/runtime/core/function.go @@ -3,15 +3,12 @@ package core import ( "context" "fmt" + "strings" ) const MaxArgs = 65536 type ( - Function = func(ctx context.Context, args ...Value) (Value, error) - - Functions map[string]Function - Namespace interface { Namespace(name string) Namespace RegisterFunction(name string, fun Function) error @@ -36,3 +33,29 @@ func ValidateArgs(args []Value, minimum, maximum int) error { return nil } + +type ( + // Functions is a map of functions and their names. + Functions map[string]Function + + // Function is a common interface for all functions of FQL. + Function = func(ctx context.Context, args ...Value) (Value, error) +) + +// Get returns the function with the given name. If the function +// does not exist it returns nil, false. +func (fns Functions) Get(name string) (Function, bool) { + fn, exists := fns[strings.ToUpper(name)] + return fn, exists +} + +// Set sets the function with the given name. If the function +// with the such name already exists it will be overwritten. +func (fns Functions) Set(name string, fn Function) { + fns[strings.ToUpper(name)] = fn +} + +// Unset delete the function with the given name. +func (fns Functions) Unset(name string) { + delete(fns, strings.ToUpper(name)) +} diff --git a/pkg/stdlib/datetime/lib.go b/pkg/stdlib/datetime/lib.go index 3daa77b2..55d7436c 100644 --- a/pkg/stdlib/datetime/lib.go +++ b/pkg/stdlib/datetime/lib.go @@ -2,8 +2,8 @@ package datetime import "github.com/MontFerret/ferret/pkg/runtime/core" -func NewLib() map[string]core.Function { - return map[string]core.Function{ +func NewLib() core.Functions { + return core.Functions{ "NOW": Now, "DATE": Date, "DATE_DAYOFWEEK": DateDayOfWeek,