github.com/NeowayLabs/nash@v0.2.2-0.20200127205349-a227041ffd50/internal/sh/fndef.go (about) 1 package sh 2 3 import ( 4 "io" 5 6 "github.com/madlambda/nash/ast" 7 "github.com/madlambda/nash/errors" 8 "github.com/madlambda/nash/internal/sh/builtin" 9 "github.com/madlambda/nash/sh" 10 ) 11 12 type ( 13 fnDef struct { 14 name string 15 Parent *Shell 16 Body *ast.Tree 17 argNames []sh.FnArg 18 19 stdin io.Reader 20 stdout, stderr io.Writer 21 environ []string 22 } 23 24 userFnDef struct { 25 *fnDef 26 } 27 28 builtinFnDef struct { 29 *fnDef 30 constructor builtin.Constructor 31 } 32 ) 33 34 // newFnDef creates a new function definition 35 func newFnDef(name string, parent *Shell, args []*ast.FnArgNode, body *ast.Tree) (*fnDef, error) { 36 fn := fnDef{ 37 name: name, 38 Parent: parent, 39 Body: body, 40 stdin: parent.stdin, 41 stdout: parent.stdout, 42 stderr: parent.stderr, 43 } 44 45 for i := 0; i < len(args); i++ { 46 arg := args[i] 47 48 if i < len(args)-1 && arg.IsVariadic { 49 return nil, errors.NewEvalError(parent.filename, 50 arg, "Vararg '%s' isn't the last argument", 51 arg.String()) 52 } 53 54 fn.argNames = append(fn.argNames, sh.FnArg{arg.Name, arg.IsVariadic}) 55 } 56 return &fn, nil 57 } 58 59 func (fnDef *fnDef) Name() string { return fnDef.name } 60 func (fnDef *fnDef) ArgNames() []sh.FnArg { return fnDef.argNames } 61 func (fnDef *fnDef) Environ() []string { return fnDef.environ } 62 63 func (fnDef *fnDef) SetEnviron(env []string) { 64 fnDef.environ = env 65 } 66 67 func (fnDef *fnDef) SetStdin(r io.Reader) { 68 fnDef.stdin = r 69 } 70 71 func (fnDef *fnDef) SetStderr(w io.Writer) { 72 fnDef.stderr = w 73 } 74 75 func (fnDef *fnDef) SetStdout(w io.Writer) { 76 fnDef.stdout = w 77 } 78 79 func (fnDef *fnDef) Stdin() io.Reader { return fnDef.stdin } 80 func (fnDef *fnDef) Stdout() io.Writer { return fnDef.stdout } 81 func (fnDef *fnDef) Stderr() io.Writer { return fnDef.stderr } 82 83 func newUserFnDef(name string, parent *Shell, args []*ast.FnArgNode, body *ast.Tree) (*userFnDef, error) { 84 fnDef, err := newFnDef(name, parent, args, body) 85 if err != nil { 86 return nil, err 87 } 88 ufndef := userFnDef{ 89 fnDef: fnDef, 90 } 91 return &ufndef, nil 92 } 93 94 func (ufnDef *userFnDef) Build() sh.Fn { 95 userfn := NewUserFn(ufnDef.Name(), ufnDef.ArgNames(), ufnDef.Body, ufnDef.Parent) 96 userfn.SetStdin(ufnDef.stdin) 97 userfn.SetStdout(ufnDef.stdout) 98 userfn.SetStderr(ufnDef.stderr) 99 userfn.SetEnviron(ufnDef.environ) 100 return userfn 101 } 102 103 func newBuiltinFnDef(name string, parent *Shell, constructor builtin.Constructor) *builtinFnDef { 104 return &builtinFnDef{ 105 fnDef: &fnDef{ 106 name: name, 107 stdin: parent.stdin, 108 stdout: parent.stdout, 109 stderr: parent.stderr, 110 }, 111 constructor: constructor, 112 } 113 } 114 115 func (bfnDef *builtinFnDef) Build() sh.Fn { 116 return NewBuiltinFn(bfnDef.Name(), 117 bfnDef.constructor(), 118 bfnDef.stdin, 119 bfnDef.stdout, 120 bfnDef.stderr, 121 ) 122 }