123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- package muesli
- import "fmt"
- import "strings"
- // LookupFallback is a fallback function that can be set to be called when
- // lookup in a scope fails
- type LookupFallback func (name string) Value
- // Scope of symbols defined in the VM, hierarchical
- type Scope struct {
- parent *Scope
- children []*Scope
- symbols map[string]Value
- fallback LookupFallback
- }
- func NewScope(parent *Scope) *Scope {
- return &Scope{parent, make([]*Scope, 0), make(map[string]Value), nil}
- }
- // Sets a lookup fall back to be called before trying the parent scope.
- // Returns the previous lookup fallback, or nil if it was nil.
- func (scope * Scope) SetLookupFallback(fb LookupFallback) LookupFallback {
- res := scope.fallback
- scope.fallback = fb
- return res
- }
- // Lookup looks up a value of a name registered in the current scope,
- // and if not found there, recursively in the parent scope.
- // Returns NilValue if not found.
- func (scope *Scope) Lookup(name string) Value {
- value, ok := scope.symbols[name]
- if ok {
- return value
- }
- if scope.fallback != nil {
- return scope.fallback(name)
- }
- if scope.parent != nil {
- return scope.parent.Lookup(name)
- }
- return NilValue
- }
- func (scope *Scope) Register(name string, value Value) Value {
- scope.symbols[name] = value
- return value
- }
- func (scope * Scope) Known(filter func(string, Value) bool) map[string]Value {
- res := make(map[string]Value)
- if scope.parent != nil {
- res = scope.parent.Known(filter)
- }
- for k, v := range scope.symbols {
- if (filter == nil) || filter(k, v) {
- res[k] = v
- }
- }
- return res
- }
- func (scope * Scope) ForEachDefined(do func(string, Value) (bool, error)) (bool, error) {
- var res bool = true
- var err error
-
- if (do == nil) {
- return false, fmt.Errorf("do may not be nil")
- }
-
- if scope.parent != nil {
- res, err = scope.parent.ForEachDefined(do)
- }
- if res == false || err != nil {
- return res, err
- }
- for k, v := range scope.symbols {
- res, err = do(k, v)
- if res == false || err != nil {
- return res, err
- }
- }
- return res, err
- }
- func (scope* Scope) DefinedHelpers() []Helper {
- res := []Helper{}
- scope.ForEachDefined(func (k string, v Value) (bool, error) {
- helper, hok := v.(Helper)
- if hok {
- res = append(res, helper)
- }
- return true, nil
- })
- return res
- }
- func (scope* Scope) DefinedNamesLike(prefix string) []string {
- res := []string{}
- scope.ForEachDefined(func (k string, v Value) (bool, error) {
- if strings.HasPrefix(k, prefix) {
- res = append(res, k)
- }
- return true, nil
- })
- return res
- }
|