github.com/MontFerret/ferret@v0.18.0/pkg/compiler/namespace.go (about)

     1  package compiler
     2  
     3  import (
     4  	"regexp"
     5  	"strings"
     6  
     7  	"github.com/pkg/errors"
     8  
     9  	"github.com/MontFerret/ferret/pkg/runtime/core"
    10  )
    11  
    12  var fnNameValidation = regexp.MustCompile("^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)*$")
    13  
    14  const emptyNS = ""
    15  const separator = "::"
    16  
    17  type NamespaceContainer struct {
    18  	funcs *core.Functions
    19  	name  string
    20  }
    21  
    22  func newRootNamespace() *NamespaceContainer {
    23  	ns := new(NamespaceContainer)
    24  	ns.funcs = core.NewFunctions()
    25  
    26  	return ns
    27  }
    28  
    29  func newNamespace(funcs *core.Functions, name string) *NamespaceContainer {
    30  	return &NamespaceContainer{funcs, strings.ToUpper(name)}
    31  }
    32  
    33  func (nc *NamespaceContainer) Namespace(name string) core.Namespace {
    34  	return newNamespace(nc.funcs, nc.makeFullName(name))
    35  }
    36  
    37  func (nc *NamespaceContainer) MustRegisterFunction(name string, fun core.Function) {
    38  	if err := nc.RegisterFunction(name, fun); err != nil {
    39  		panic(err)
    40  	}
    41  }
    42  
    43  func (nc *NamespaceContainer) RegisterFunction(name string, fun core.Function) error {
    44  	nsName := nc.makeFullName(name)
    45  
    46  	_, exists := nc.funcs.Get(nsName)
    47  
    48  	if exists {
    49  		return errors.Errorf("function already exists: %s", name)
    50  	}
    51  
    52  	// validation the name
    53  	if strings.Contains(name, separator) {
    54  		return errors.Errorf("invalid function name: %s", name)
    55  	}
    56  
    57  	if !fnNameValidation.MatchString(nsName) {
    58  		return errors.Errorf("invalid function or namespace name: %s", nsName)
    59  	}
    60  
    61  	nc.funcs.Set(nsName, fun)
    62  
    63  	return nil
    64  }
    65  
    66  func (nc *NamespaceContainer) RemoveFunction(name string) {
    67  	nc.funcs.Unset(nc.makeFullName(name))
    68  }
    69  
    70  func (nc *NamespaceContainer) MustRegisterFunctions(funcs *core.Functions) {
    71  	if err := nc.RegisterFunctions(funcs); err != nil {
    72  		panic(err)
    73  	}
    74  }
    75  
    76  func (nc *NamespaceContainer) RegisterFunctions(funcs *core.Functions) error {
    77  	for _, name := range funcs.Names() {
    78  		fun, _ := funcs.Get(name)
    79  
    80  		if err := nc.RegisterFunction(name, fun); err != nil {
    81  			return err
    82  		}
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  func (nc *NamespaceContainer) RegisteredFunctions() []string {
    89  	fnames := nc.funcs.Names()
    90  	res := make([]string, 0, len(fnames))
    91  
    92  	// root namespace, return all functions
    93  	if nc.name == emptyNS {
    94  		res = append(res, fnames...)
    95  	} else {
    96  		nsPrefix := nc.name + separator
    97  		for _, k := range fnames {
    98  			if strings.HasPrefix(k, nsPrefix) {
    99  				res = append(res, k)
   100  			}
   101  		}
   102  	}
   103  
   104  	return res
   105  }
   106  
   107  func (nc *NamespaceContainer) makeFullName(name string) string {
   108  	if nc.name == emptyNS {
   109  		return name
   110  	}
   111  
   112  	return nc.name + separator + name
   113  }