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  }