package compiler import ( "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_]*)*$") const emptyNS = "" const separator = "::" type NamespaceContainer struct { funcs *core.Functions name string } func newRootNamespace() *NamespaceContainer { ns := new(NamespaceContainer) ns.funcs = core.NewFunctions() return ns } func newNamespace(funcs *core.Functions, name string) *NamespaceContainer { return &NamespaceContainer{funcs, strings.ToUpper(name)} } func (nc *NamespaceContainer) Namespace(name string) core.Namespace { return newNamespace(nc.funcs, nc.makeFullName(name)) } func (nc *NamespaceContainer) RegisterFunction(name string, fun core.Function) error { nsName := nc.makeFullName(name) _, exists := nc.funcs.Get(nsName) if exists { return errors.Errorf("function already exists: %s", name) } // validation the name if strings.Contains(name, separator) { return errors.Errorf("invalid function name: %s", name) } if !fnNameValidation.MatchString(nsName) { return errors.Errorf("invalid function or namespace name: %s", nsName) } nc.funcs.Set(nsName, fun) return nil } func (nc *NamespaceContainer) RemoveFunction(name string) { nc.funcs.Unset(nc.makeFullName(name)) } func (nc *NamespaceContainer) RegisterFunctions(funcs *core.Functions) error { for _, name := range funcs.Names() { fun, _ := funcs.Get(name) if err := nc.RegisterFunction(name, fun); err != nil { return err } } return nil } func (nc *NamespaceContainer) RegisteredFunctions() []string { fnames := nc.funcs.Names() res := make([]string, 0, len(fnames)) // root namespace, return all functions if nc.name == emptyNS { for _, k := range fnames { res = append(res, k) } } else { nsPrefix := nc.name + separator for _, k := range fnames { if strings.HasPrefix(k, nsPrefix) { res = append(res, k) } } } return res } func (nc *NamespaceContainer) makeFullName(name string) string { if nc.name == emptyNS { return name } return nc.name + separator + name }