func (n NodeCommand) Eval(scp *variables.Scope, ioc *T.IOContainer) T.ExitStatus { // A line with only assignments applies them to the Root Scope // We check this first to avoid unnecessary scope Push/Pop's if len(n.Args) == 0 { for k, v := range n.Assign { scp.Set(k, v.Expand(scp)) } return T.ExitSuccess } // Minimum of len(n.Args) after expansions, Likely // that it will be more after globbing though expandedArgs := []string{} for _, arg := range n.Args { expandedArgs = append(expandedArgs, arg.Expand(scp)) } // Order of precedence: // Relative command > Builtin > User Function > Other external command command := expandedArgs[0] builtinFunc, builtinFound := builtins.All[command] userFunc, userFuncFound := scp.Functions[command] if strings.ContainsRune(command, '/') || (!builtinFound && !userFuncFound) { scp.Push() defer scp.Pop() for k, v := range n.Assign { scp.Set(k, v.Expand(scp), variables.LocalScope) } return n.execExternal(scp, ioc, expandedArgs) } if builtinFound { return builtinFunc(scp, ioc, expandedArgs[1:]) } if userFuncFound { x := userFunc.(NodeFunction) return x.EvalFunc(scp, ioc, expandedArgs[1:]) } return T.ExitUnknownCommand }
func (n NodeFunction) EvalFunc(scp *variables.Scope, ioc *T.IOContainer, args []string) T.ExitStatus { scp.PushFunction(args) defer scp.Pop() return n.Body.Eval(scp, ioc) }