package ucl type evalCtx struct { root *evalCtx parent *evalCtx commands map[string]invokable macros map[string]macroable vars map[string]Object pseudoVars map[string]pseudoVar } func (ec *evalCtx) forkAndIsolate() *evalCtx { newEc := &evalCtx{parent: ec} newEc.root = newEc return newEc } func (ec *evalCtx) fork() *evalCtx { return &evalCtx{parent: ec, root: ec.root} } func (ec *evalCtx) addCmd(name string, inv invokable) { if ec.root.commands == nil { ec.root.commands = make(map[string]invokable) } ec.root.commands[name] = inv } func (ec *evalCtx) addMacro(name string, inv macroable) { if ec.root.macros == nil { ec.root.macros = make(map[string]macroable) } ec.root.macros[name] = inv } func (ec *evalCtx) setVar(name string, val Object) bool { if ec == nil || ec.vars == nil { return false } if _, ok := ec.vars[name]; ok { ec.vars[name] = val return true } return ec.parent.setVar(name, val) } func (ec *evalCtx) setOrDefineVar(name string, val Object) { if ec.setVar(name, val) { return } if ec.vars == nil { ec.vars = make(map[string]Object) } ec.vars[name] = val } func (ec *evalCtx) getVar(name string) (Object, bool) { if ec.vars == nil { if ec.parent == nil { return nil, false } return ec.parent.getVar(name) } if v, ok := ec.vars[name]; ok { return v, true } else if ec.parent != nil { return ec.parent.getVar(name) } return nil, false } func (ec *evalCtx) getPseudoVar(name string) (pseudoVar, bool) { if ec.root.pseudoVars == nil { return nil, false } pvar, ok := ec.root.pseudoVars[name] return pvar, ok } func (ec *evalCtx) lookupInvokable(name string) invokable { if ec == nil { return nil } for e := ec; e != nil; e = e.parent { if cmd, ok := e.commands[name]; ok { return cmd } } return ec.parent.lookupInvokable(name) } func (ec *evalCtx) lookupMacro(name string) macroable { if ec == nil { return nil } for e := ec; e != nil; e = e.parent { if cmd, ok := e.macros[name]; ok { return cmd } } return ec.parent.lookupMacro(name) }