github.com/benhoyt/goawk@v1.8.1/interp/interp.go (about)

     1  // Package interp is the GoAWK interpreter (a simple tree-walker).
     2  //
     3  // For basic usage, use the Exec function. For more complicated use
     4  // cases and configuration options, first use the parser package to
     5  // parse the AWK source, and then use ExecProgram to execute it with
     6  // a specific configuration.
     7  //
     8  package interp
     9  
    10  import (
    11  	"bufio"
    12  	"errors"
    13  	"fmt"
    14  	"io"
    15  	"io/ioutil"
    16  	"math"
    17  	"math/rand"
    18  	"os"
    19  	"os/exec"
    20  	"regexp"
    21  	"runtime"
    22  	"strconv"
    23  	"strings"
    24  	"unicode/utf8"
    25  
    26  	. "github.com/benhoyt/goawk/internal/ast"
    27  	. "github.com/benhoyt/goawk/lexer"
    28  	. "github.com/benhoyt/goawk/parser"
    29  )
    30  
    31  var (
    32  	errExit     = errors.New("exit")
    33  	errBreak    = errors.New("break")
    34  	errContinue = errors.New("continue")
    35  	errNext     = errors.New("next")
    36  
    37  	crlfNewline = runtime.GOOS == "windows"
    38  	varRegex    = regexp.MustCompile(`^([_a-zA-Z][_a-zA-Z0-9]*)=(.*)`)
    39  )
    40  
    41  // Error (actually *Error) is returned by Exec and Eval functions on
    42  // interpreter error, for example a negative field index.
    43  type Error struct {
    44  	message string
    45  }
    46  
    47  func (e *Error) Error() string {
    48  	return e.message
    49  }
    50  
    51  func newError(format string, args ...interface{}) error {
    52  	return &Error{fmt.Sprintf(format, args...)}
    53  }
    54  
    55  type returnValue struct {
    56  	Value value
    57  }
    58  
    59  func (r returnValue) Error() string {
    60  	return "<return " + r.Value.str("%.6g") + ">"
    61  }
    62  
    63  type interp struct {
    64  	// Input/output
    65  	output        io.Writer
    66  	errorOutput   io.Writer
    67  	scanner       *bufio.Scanner
    68  	scanners      map[string]*bufio.Scanner
    69  	stdin         io.Reader
    70  	filenameIndex int
    71  	hadFiles      bool
    72  	input         io.Reader
    73  	inputStreams  map[string]io.ReadCloser
    74  	outputStreams map[string]io.WriteCloser
    75  	commands      map[string]*exec.Cmd
    76  	noExec        bool
    77  	noFileWrites  bool
    78  	noFileReads   bool
    79  
    80  	// Scalars, arrays, and function state
    81  	globals     []value
    82  	stack       []value
    83  	frame       []value
    84  	arrays      []map[string]value
    85  	localArrays [][]int
    86  	callDepth   int
    87  	nativeFuncs []nativeFunc
    88  
    89  	// File, line, and field handling
    90  	filename    string
    91  	line        string
    92  	lineNum     int
    93  	fileLineNum int
    94  	fields      []string
    95  	numFields   int
    96  	haveFields  bool
    97  
    98  	// Built-in variables
    99  	argc            int
   100  	convertFormat   string
   101  	outputFormat    string
   102  	fieldSep        string
   103  	fieldSepRegex   *regexp.Regexp
   104  	recordSep       string
   105  	outputFieldSep  string
   106  	outputRecordSep string
   107  	subscriptSep    string
   108  	matchLength     int
   109  	matchStart      int
   110  
   111  	// Misc pieces of state
   112  	program     *Program
   113  	random      *rand.Rand
   114  	randSeed    float64
   115  	exitStatus  int
   116  	regexCache  map[string]*regexp.Regexp
   117  	formatCache map[string]cachedFormat
   118  }
   119  
   120  // Various const configuration. Could make these part of Config if
   121  // we wanted to, but no need for now.
   122  const (
   123  	maxCachedRegexes = 100
   124  	maxCachedFormats = 100
   125  	maxRecordLength  = 10 * 1024 * 1024 // 10MB seems like plenty
   126  	maxFieldIndex    = 1000000
   127  	maxCallDepth     = 1000
   128  	initialStackSize = 100
   129  	outputBufSize    = 64 * 1024
   130  	inputBufSize     = 64 * 1024
   131  )
   132  
   133  // Config defines the interpreter configuration for ExecProgram.
   134  type Config struct {
   135  	// Standard input reader (defaults to os.Stdin)
   136  	Stdin io.Reader
   137  
   138  	// Writer for normal output (defaults to a buffered version of
   139  	// os.Stdout)
   140  	Output io.Writer
   141  
   142  	// Writer for non-fatal error messages (defaults to os.Stderr)
   143  	Error io.Writer
   144  
   145  	// The name of the executable (accessible via ARGV[0])
   146  	Argv0 string
   147  
   148  	// Input arguments (usually filenames): empty slice means read
   149  	// only from Stdin, and a filename of "-" means read from Stdin
   150  	// instead of a real file.
   151  	Args []string
   152  
   153  	// List of name-value pairs for variables to set before executing
   154  	// the program (useful for setting FS and other built-in
   155  	// variables, for example []string{"FS", ",", "OFS", ","}).
   156  	Vars []string
   157  
   158  	// Map of named Go functions to allow calling from AWK. You need
   159  	// to pass this same map to the parser.ParseProgram config.
   160  	//
   161  	// Functions can have any number of parameters, and variadic
   162  	// functions are supported. Functions can have no return values,
   163  	// one return value, or two return values (result, error). In the
   164  	// two-value case, if the function returns a non-nil error,
   165  	// program execution will stop and ExecProgram will return that
   166  	// error.
   167  	//
   168  	// Apart from the error return value, the types supported are
   169  	// bool, integer and floating point types (excluding complex),
   170  	// and string types (string or []byte).
   171  	//
   172  	// It's not an error to call a Go function from AWK with fewer
   173  	// arguments than it has parameters in Go. In this case, the zero
   174  	// value will be used for any additional parameters. However, it
   175  	// is a parse error to call a non-variadic function from AWK with
   176  	// more arguments than it has parameters in Go.
   177  	//
   178  	// Functions defined with the "function" keyword in AWK code
   179  	// take precedence over functions in Funcs.
   180  	Funcs map[string]interface{}
   181  
   182  	// Set one or more of these to true to prevent unsafe behaviours,
   183  	// useful when executing untrusted scripts:
   184  	//
   185  	// * NoExec prevents system calls via system() or pipe operator
   186  	// * NoFileWrites prevents writing to files via '>' or '>>'
   187  	// * NoFileReads prevents reading from files via getline or the
   188  	//   filenames in Args
   189  	NoExec       bool
   190  	NoFileWrites bool
   191  	NoFileReads  bool
   192  }
   193  
   194  // ExecProgram executes the parsed program using the given interpreter
   195  // config, returning the exit status code of the program. Error is nil
   196  // on successful execution of the program, even if the program returns
   197  // a non-zero status code.
   198  func ExecProgram(program *Program, config *Config) (int, error) {
   199  	if len(config.Vars)%2 != 0 {
   200  		return 0, newError("length of config.Vars must be a multiple of 2, not %d", len(config.Vars))
   201  	}
   202  
   203  	p := &interp{program: program}
   204  
   205  	// Allocate memory for variables
   206  	p.globals = make([]value, len(program.Scalars))
   207  	p.stack = make([]value, 0, initialStackSize)
   208  	p.arrays = make([]map[string]value, len(program.Arrays), len(program.Arrays)+initialStackSize)
   209  	for i := 0; i < len(program.Arrays); i++ {
   210  		p.arrays[i] = make(map[string]value)
   211  	}
   212  
   213  	// Initialize defaults
   214  	p.regexCache = make(map[string]*regexp.Regexp, 10)
   215  	p.formatCache = make(map[string]cachedFormat, 10)
   216  	p.randSeed = 1.0
   217  	seed := math.Float64bits(p.randSeed)
   218  	p.random = rand.New(rand.NewSource(int64(seed)))
   219  	p.convertFormat = "%.6g"
   220  	p.outputFormat = "%.6g"
   221  	p.fieldSep = " "
   222  	p.recordSep = "\n"
   223  	p.outputFieldSep = " "
   224  	p.outputRecordSep = "\n"
   225  	p.subscriptSep = "\x1c"
   226  	p.noExec = config.NoExec
   227  	p.noFileWrites = config.NoFileWrites
   228  	p.noFileReads = config.NoFileReads
   229  	err := p.initNativeFuncs(config.Funcs)
   230  	if err != nil {
   231  		return 0, err
   232  	}
   233  
   234  	// Setup ARGV and other variables from config
   235  	argvIndex := program.Arrays["ARGV"]
   236  	p.setArrayValue(ScopeGlobal, argvIndex, "0", str(config.Argv0))
   237  	p.argc = len(config.Args) + 1
   238  	for i, arg := range config.Args {
   239  		p.setArrayValue(ScopeGlobal, argvIndex, strconv.Itoa(i+1), str(arg))
   240  	}
   241  	p.filenameIndex = 1
   242  	p.hadFiles = false
   243  	for i := 0; i < len(config.Vars); i += 2 {
   244  		err := p.setVarByName(config.Vars[i], config.Vars[i+1])
   245  		if err != nil {
   246  			return 0, err
   247  		}
   248  	}
   249  
   250  	// Setup I/O structures
   251  	p.stdin = config.Stdin
   252  	if p.stdin == nil {
   253  		p.stdin = os.Stdin
   254  	}
   255  	p.output = config.Output
   256  	if p.output == nil {
   257  		p.output = bufio.NewWriterSize(os.Stdout, outputBufSize)
   258  	}
   259  	p.errorOutput = config.Error
   260  	if p.errorOutput == nil {
   261  		p.errorOutput = os.Stderr
   262  	}
   263  	p.inputStreams = make(map[string]io.ReadCloser)
   264  	p.outputStreams = make(map[string]io.WriteCloser)
   265  	p.commands = make(map[string]*exec.Cmd)
   266  	p.scanners = make(map[string]*bufio.Scanner)
   267  	defer p.closeAll()
   268  
   269  	// Execute the program! BEGIN, then pattern/actions, then END
   270  	err = p.execBeginEnd(program.Begin)
   271  	if err != nil && err != errExit {
   272  		return 0, err
   273  	}
   274  	if program.Actions == nil && program.End == nil {
   275  		return p.exitStatus, nil
   276  	}
   277  	if err != errExit {
   278  		err = p.execActions(program.Actions)
   279  		if err != nil && err != errExit {
   280  			return 0, err
   281  		}
   282  	}
   283  	err = p.execBeginEnd(program.End)
   284  	if err != nil && err != errExit {
   285  		return 0, err
   286  	}
   287  	return p.exitStatus, nil
   288  }
   289  
   290  // Exec provides a simple way to parse and execute an AWK program
   291  // with the given field separator. Exec reads input from the given
   292  // reader (nil means use os.Stdin) and writes output to stdout (nil
   293  // means use a buffered version of os.Stdout).
   294  func Exec(source, fieldSep string, input io.Reader, output io.Writer) error {
   295  	prog, err := ParseProgram([]byte(source), nil)
   296  	if err != nil {
   297  		return err
   298  	}
   299  	config := &Config{
   300  		Stdin:  input,
   301  		Output: output,
   302  		Error:  ioutil.Discard,
   303  		Vars:   []string{"FS", fieldSep},
   304  	}
   305  	_, err = ExecProgram(prog, config)
   306  	return err
   307  }
   308  
   309  // Execute BEGIN or END blocks (may be multiple)
   310  func (p *interp) execBeginEnd(beginEnd []Stmts) error {
   311  	for _, statements := range beginEnd {
   312  		err := p.executes(statements)
   313  		if err != nil {
   314  			return err
   315  		}
   316  	}
   317  	return nil
   318  }
   319  
   320  // Execute pattern-action blocks (may be multiple)
   321  func (p *interp) execActions(actions []Action) error {
   322  	inRange := make([]bool, len(actions))
   323  lineLoop:
   324  	for {
   325  		// Read and setup next line of input
   326  		line, err := p.nextLine()
   327  		if err == io.EOF {
   328  			break
   329  		}
   330  		if err != nil {
   331  			return err
   332  		}
   333  		p.setLine(line)
   334  
   335  		// Execute all the pattern-action blocks for each line
   336  		for i, action := range actions {
   337  			// First determine whether the pattern matches
   338  			matched := false
   339  			switch len(action.Pattern) {
   340  			case 0:
   341  				// No pattern is equivalent to pattern evaluating to true
   342  				matched = true
   343  			case 1:
   344  				// Single boolean pattern
   345  				v, err := p.eval(action.Pattern[0])
   346  				if err != nil {
   347  					return err
   348  				}
   349  				matched = v.boolean()
   350  			case 2:
   351  				// Range pattern (matches between start and stop lines)
   352  				if !inRange[i] {
   353  					v, err := p.eval(action.Pattern[0])
   354  					if err != nil {
   355  						return err
   356  					}
   357  					inRange[i] = v.boolean()
   358  				}
   359  				matched = inRange[i]
   360  				if inRange[i] {
   361  					v, err := p.eval(action.Pattern[1])
   362  					if err != nil {
   363  						return err
   364  					}
   365  					inRange[i] = !v.boolean()
   366  				}
   367  			}
   368  			if !matched {
   369  				continue
   370  			}
   371  
   372  			// No action is equivalent to { print $0 }
   373  			if action.Stmts == nil {
   374  				err := p.printLine(p.output, p.line)
   375  				if err != nil {
   376  					return err
   377  				}
   378  				continue
   379  			}
   380  
   381  			// Execute the body statements
   382  			err := p.executes(action.Stmts)
   383  			if err == errNext {
   384  				// "next" statement skips straight to next line
   385  				continue lineLoop
   386  			}
   387  			if err != nil {
   388  				return err
   389  			}
   390  		}
   391  	}
   392  	return nil
   393  }
   394  
   395  // Execute a block of multiple statements
   396  func (p *interp) executes(stmts Stmts) error {
   397  	for _, s := range stmts {
   398  		err := p.execute(s)
   399  		if err != nil {
   400  			return err
   401  		}
   402  	}
   403  	return nil
   404  }
   405  
   406  // Execute a single statement
   407  func (p *interp) execute(stmt Stmt) error {
   408  	switch s := stmt.(type) {
   409  	case *ExprStmt:
   410  		// Expression statement: simply throw away the expression value
   411  		_, err := p.eval(s.Expr)
   412  		return err
   413  
   414  	case *PrintStmt:
   415  		// Print OFS-separated args followed by ORS (usually newline)
   416  		var line string
   417  		if len(s.Args) > 0 {
   418  			strs := make([]string, len(s.Args))
   419  			for i, a := range s.Args {
   420  				v, err := p.eval(a)
   421  				if err != nil {
   422  					return err
   423  				}
   424  				strs[i] = v.str(p.outputFormat)
   425  			}
   426  			line = strings.Join(strs, p.outputFieldSep)
   427  		} else {
   428  			// "print" with no args is equivalent to "print $0"
   429  			line = p.line
   430  		}
   431  		output, err := p.getOutputStream(s.Redirect, s.Dest)
   432  		if err != nil {
   433  			return err
   434  		}
   435  		return p.printLine(output, line)
   436  
   437  	case *PrintfStmt:
   438  		// printf(fmt, arg1, arg2, ...): uses our version of sprintf
   439  		// to build the formatted string and then print that
   440  		formatValue, err := p.eval(s.Args[0])
   441  		if err != nil {
   442  			return err
   443  		}
   444  		format := p.toString(formatValue)
   445  		args := make([]value, len(s.Args)-1)
   446  		for i, a := range s.Args[1:] {
   447  			args[i], err = p.eval(a)
   448  			if err != nil {
   449  				return err
   450  			}
   451  		}
   452  		output, err := p.getOutputStream(s.Redirect, s.Dest)
   453  		if err != nil {
   454  			return err
   455  		}
   456  		str, err := p.sprintf(format, args)
   457  		if err != nil {
   458  			return err
   459  		}
   460  		err = writeOutput(output, str)
   461  		if err != nil {
   462  			return err
   463  		}
   464  
   465  	case *IfStmt:
   466  		v, err := p.eval(s.Cond)
   467  		if err != nil {
   468  			return err
   469  		}
   470  		if v.boolean() {
   471  			return p.executes(s.Body)
   472  		} else {
   473  			// Doesn't do anything if s.Else is nil
   474  			return p.executes(s.Else)
   475  		}
   476  
   477  	case *ForStmt:
   478  		// C-like for loop with pre-statement, cond, and post-statement
   479  		if s.Pre != nil {
   480  			err := p.execute(s.Pre)
   481  			if err != nil {
   482  				return err
   483  			}
   484  		}
   485  		for {
   486  			if s.Cond != nil {
   487  				v, err := p.eval(s.Cond)
   488  				if err != nil {
   489  					return err
   490  				}
   491  				if !v.boolean() {
   492  					break
   493  				}
   494  			}
   495  			err := p.executes(s.Body)
   496  			if err == errBreak {
   497  				break
   498  			}
   499  			if err != nil && err != errContinue {
   500  				return err
   501  			}
   502  			if s.Post != nil {
   503  				err := p.execute(s.Post)
   504  				if err != nil {
   505  					return err
   506  				}
   507  			}
   508  		}
   509  
   510  	case *ForInStmt:
   511  		// Foreach-style "for (key in array)" loop
   512  		array := p.arrays[p.getArrayIndex(s.Array.Scope, s.Array.Index)]
   513  		for index := range array {
   514  			err := p.setVar(s.Var.Scope, s.Var.Index, str(index))
   515  			if err != nil {
   516  				return err
   517  			}
   518  			err = p.executes(s.Body)
   519  			if err == errBreak {
   520  				break
   521  			}
   522  			if err == errContinue {
   523  				continue
   524  			}
   525  			if err != nil {
   526  				return err
   527  			}
   528  		}
   529  
   530  	case *ReturnStmt:
   531  		// Return statement uses special error value which is "caught"
   532  		// by the callUser function
   533  		var v value
   534  		if s.Value != nil {
   535  			var err error
   536  			v, err = p.eval(s.Value)
   537  			if err != nil {
   538  				return err
   539  			}
   540  		}
   541  		return returnValue{v}
   542  
   543  	case *WhileStmt:
   544  		// Simple "while (cond)" loop
   545  		for {
   546  			v, err := p.eval(s.Cond)
   547  			if err != nil {
   548  				return err
   549  			}
   550  			if !v.boolean() {
   551  				break
   552  			}
   553  			err = p.executes(s.Body)
   554  			if err == errBreak {
   555  				break
   556  			}
   557  			if err == errContinue {
   558  				continue
   559  			}
   560  			if err != nil {
   561  				return err
   562  			}
   563  		}
   564  
   565  	case *DoWhileStmt:
   566  		// Do-while loop (tests condition after executing body)
   567  		for {
   568  			err := p.executes(s.Body)
   569  			if err == errBreak {
   570  				break
   571  			}
   572  			if err == errContinue {
   573  				continue
   574  			}
   575  			if err != nil {
   576  				return err
   577  			}
   578  			v, err := p.eval(s.Cond)
   579  			if err != nil {
   580  				return err
   581  			}
   582  			if !v.boolean() {
   583  				break
   584  			}
   585  		}
   586  
   587  	// Break, continue, next, and exit statements
   588  	case *BreakStmt:
   589  		return errBreak
   590  	case *ContinueStmt:
   591  		return errContinue
   592  	case *NextStmt:
   593  		return errNext
   594  	case *ExitStmt:
   595  		if s.Status != nil {
   596  			status, err := p.eval(s.Status)
   597  			if err != nil {
   598  				return err
   599  			}
   600  			p.exitStatus = int(status.num())
   601  		}
   602  		// Return special errExit value "caught" by top-level executor
   603  		return errExit
   604  
   605  	case *DeleteStmt:
   606  		if len(s.Index) > 0 {
   607  			// Delete single key from array
   608  			index, err := p.evalIndex(s.Index)
   609  			if err != nil {
   610  				return err
   611  			}
   612  			array := p.arrays[p.getArrayIndex(s.Array.Scope, s.Array.Index)]
   613  			delete(array, index) // Does nothing if key isn't present
   614  		} else {
   615  			// Delete entire array
   616  			array := p.arrays[p.getArrayIndex(s.Array.Scope, s.Array.Index)]
   617  			for k := range array {
   618  				delete(array, k)
   619  			}
   620  		}
   621  
   622  	case *BlockStmt:
   623  		// Nested block (just syntax, doesn't do anything)
   624  		return p.executes(s.Body)
   625  
   626  	default:
   627  		// Should never happen
   628  		panic(fmt.Sprintf("unexpected stmt type: %T", stmt))
   629  	}
   630  	return nil
   631  }
   632  
   633  // Evaluate a single expression, return expression value and error
   634  func (p *interp) eval(expr Expr) (value, error) {
   635  	switch e := expr.(type) {
   636  	case *NumExpr:
   637  		// Number literal
   638  		return num(e.Value), nil
   639  
   640  	case *StrExpr:
   641  		// String literal
   642  		return str(e.Value), nil
   643  
   644  	case *FieldExpr:
   645  		// $n field expression
   646  		index, err := p.eval(e.Index)
   647  		if err != nil {
   648  			return null(), err
   649  		}
   650  		return p.getField(int(index.num()))
   651  
   652  	case *VarExpr:
   653  		// Variable read expression (scope is global, local, or special)
   654  		return p.getVar(e.Scope, e.Index), nil
   655  
   656  	case *RegExpr:
   657  		// Stand-alone /regex/ is equivalent to: $0 ~ /regex/
   658  		re, err := p.compileRegex(e.Regex)
   659  		if err != nil {
   660  			return null(), err
   661  		}
   662  		return boolean(re.MatchString(p.line)), nil
   663  
   664  	case *BinaryExpr:
   665  		// Binary expression. Note that && and || are special cases
   666  		// as they're short-circuit operators.
   667  		left, err := p.eval(e.Left)
   668  		if err != nil {
   669  			return null(), err
   670  		}
   671  		switch e.Op {
   672  		case AND:
   673  			if !left.boolean() {
   674  				return num(0), nil
   675  			}
   676  			right, err := p.eval(e.Right)
   677  			if err != nil {
   678  				return null(), err
   679  			}
   680  			return boolean(right.boolean()), nil
   681  		case OR:
   682  			if left.boolean() {
   683  				return num(1), nil
   684  			}
   685  			right, err := p.eval(e.Right)
   686  			if err != nil {
   687  				return null(), err
   688  			}
   689  			return boolean(right.boolean()), nil
   690  		default:
   691  			right, err := p.eval(e.Right)
   692  			if err != nil {
   693  				return null(), err
   694  			}
   695  			return p.evalBinary(e.Op, left, right)
   696  		}
   697  
   698  	case *IncrExpr:
   699  		// Pre-increment, post-increment, pre-decrement, post-decrement
   700  
   701  		// First evaluate the expression, but remember array or field
   702  		// index so we don't evaluate part of the expression twice
   703  		exprValue, arrayIndex, fieldIndex, err := p.evalForAugAssign(e.Expr)
   704  		if err != nil {
   705  			return null(), err
   706  		}
   707  
   708  		// Then convert to number and increment or decrement
   709  		exprNum := exprValue.num()
   710  		var incr float64
   711  		if e.Op == INCR {
   712  			incr = exprNum + 1
   713  		} else {
   714  			incr = exprNum - 1
   715  		}
   716  		incrValue := num(incr)
   717  
   718  		// Finally assign back to expression and return the correct value
   719  		err = p.assignAug(e.Expr, arrayIndex, fieldIndex, incrValue)
   720  		if err != nil {
   721  			return null(), err
   722  		}
   723  		if e.Pre {
   724  			return incrValue, nil
   725  		} else {
   726  			return num(exprNum), nil
   727  		}
   728  
   729  	case *AssignExpr:
   730  		// Assignment expression (returns right-hand side)
   731  		right, err := p.eval(e.Right)
   732  		if err != nil {
   733  			return null(), err
   734  		}
   735  		err = p.assign(e.Left, right)
   736  		if err != nil {
   737  			return null(), err
   738  		}
   739  		return right, nil
   740  
   741  	case *AugAssignExpr:
   742  		// Augmented assignment like += (returns right-hand side)
   743  		right, err := p.eval(e.Right)
   744  		if err != nil {
   745  			return null(), err
   746  		}
   747  		left, arrayIndex, fieldIndex, err := p.evalForAugAssign(e.Left)
   748  		if err != nil {
   749  			return null(), err
   750  		}
   751  		right, err = p.evalBinary(e.Op, left, right)
   752  		if err != nil {
   753  			return null(), err
   754  		}
   755  		err = p.assignAug(e.Left, arrayIndex, fieldIndex, right)
   756  		if err != nil {
   757  			return null(), err
   758  		}
   759  		return right, nil
   760  
   761  	case *CondExpr:
   762  		// C-like ?: ternary conditional operator
   763  		cond, err := p.eval(e.Cond)
   764  		if err != nil {
   765  			return null(), err
   766  		}
   767  		if cond.boolean() {
   768  			return p.eval(e.True)
   769  		} else {
   770  			return p.eval(e.False)
   771  		}
   772  
   773  	case *IndexExpr:
   774  		// Read value from array by index
   775  		index, err := p.evalIndex(e.Index)
   776  		if err != nil {
   777  			return null(), err
   778  		}
   779  		return p.getArrayValue(e.Array.Scope, e.Array.Index, index), nil
   780  
   781  	case *CallExpr:
   782  		// Call a builtin function
   783  		return p.callBuiltin(e.Func, e.Args)
   784  
   785  	case *UnaryExpr:
   786  		// Unary ! or + or -
   787  		v, err := p.eval(e.Value)
   788  		if err != nil {
   789  			return null(), err
   790  		}
   791  		return p.evalUnary(e.Op, v), nil
   792  
   793  	case *InExpr:
   794  		// "key in array" expression
   795  		index, err := p.evalIndex(e.Index)
   796  		if err != nil {
   797  			return null(), err
   798  		}
   799  		array := p.arrays[p.getArrayIndex(e.Array.Scope, e.Array.Index)]
   800  		_, ok := array[index]
   801  		return boolean(ok), nil
   802  
   803  	case *UserCallExpr:
   804  		// Call user-defined or native Go function
   805  		if e.Native {
   806  			return p.callNative(e.Index, e.Args)
   807  		} else {
   808  			return p.callUser(e.Index, e.Args)
   809  		}
   810  
   811  	case *GetlineExpr:
   812  		// Getline: read line from input
   813  		var line string
   814  		switch {
   815  		case e.Command != nil:
   816  			nameValue, err := p.eval(e.Command)
   817  			if err != nil {
   818  				return null(), err
   819  			}
   820  			name := p.toString(nameValue)
   821  			scanner, err := p.getInputScannerPipe(name)
   822  			if err != nil {
   823  				return null(), err
   824  			}
   825  			if !scanner.Scan() {
   826  				if err := scanner.Err(); err != nil {
   827  					return num(-1), nil
   828  				}
   829  				return num(0), nil
   830  			}
   831  			line = scanner.Text()
   832  		case e.File != nil:
   833  			nameValue, err := p.eval(e.File)
   834  			if err != nil {
   835  				return null(), err
   836  			}
   837  			name := p.toString(nameValue)
   838  			scanner, err := p.getInputScannerFile(name)
   839  			if err != nil {
   840  				if _, ok := err.(*os.PathError); ok {
   841  					// File not found is not a hard error, getline just returns -1.
   842  					// See: https://github.com/benhoyt/goawk/issues/41
   843  					return num(-1), nil
   844  				}
   845  				return null(), err
   846  			}
   847  			if !scanner.Scan() {
   848  				if err := scanner.Err(); err != nil {
   849  					return num(-1), nil
   850  				}
   851  				return num(0), nil
   852  			}
   853  			line = scanner.Text()
   854  		default:
   855  			var err error
   856  			line, err = p.nextLine()
   857  			if err == io.EOF {
   858  				return num(0), nil
   859  			}
   860  			if err != nil {
   861  				return num(-1), nil
   862  			}
   863  		}
   864  		if e.Var != nil {
   865  			err := p.setVar(e.Var.Scope, e.Var.Index, str(line))
   866  			if err != nil {
   867  				return null(), err
   868  			}
   869  		} else {
   870  			p.setLine(line)
   871  		}
   872  		return num(1), nil
   873  
   874  	default:
   875  		// Should never happen
   876  		panic(fmt.Sprintf("unexpected expr type: %T", expr))
   877  	}
   878  }
   879  
   880  func (p *interp) evalForAugAssign(expr Expr) (v value, arrayIndex string, fieldIndex int, err error) {
   881  	switch expr := expr.(type) {
   882  	case *VarExpr:
   883  		v = p.getVar(expr.Scope, expr.Index)
   884  	case *IndexExpr:
   885  		arrayIndex, err = p.evalIndex(expr.Index)
   886  		if err != nil {
   887  			return null(), "", 0, err
   888  		}
   889  		v = p.getArrayValue(expr.Array.Scope, expr.Array.Index, arrayIndex)
   890  	case *FieldExpr:
   891  		index, err := p.eval(expr.Index)
   892  		if err != nil {
   893  			return null(), "", 0, err
   894  		}
   895  		fieldIndex = int(index.num())
   896  		v, err = p.getField(fieldIndex)
   897  		if err != nil {
   898  			return null(), "", 0, err
   899  		}
   900  	}
   901  	return v, arrayIndex, fieldIndex, nil
   902  }
   903  
   904  func (p *interp) assignAug(expr Expr, arrayIndex string, fieldIndex int, v value) error {
   905  	switch expr := expr.(type) {
   906  	case *VarExpr:
   907  		return p.setVar(expr.Scope, expr.Index, v)
   908  	case *IndexExpr:
   909  		p.setArrayValue(expr.Array.Scope, expr.Array.Index, arrayIndex, v)
   910  	default: // *FieldExpr
   911  		return p.setField(fieldIndex, p.toString(v))
   912  	}
   913  	return nil
   914  }
   915  
   916  // Get a variable's value by index in given scope
   917  func (p *interp) getVar(scope VarScope, index int) value {
   918  	switch scope {
   919  	case ScopeGlobal:
   920  		return p.globals[index]
   921  	case ScopeLocal:
   922  		return p.frame[index]
   923  	default: // ScopeSpecial
   924  		switch index {
   925  		case V_NF:
   926  			p.ensureFields()
   927  			return num(float64(p.numFields))
   928  		case V_NR:
   929  			return num(float64(p.lineNum))
   930  		case V_RLENGTH:
   931  			return num(float64(p.matchLength))
   932  		case V_RSTART:
   933  			return num(float64(p.matchStart))
   934  		case V_FNR:
   935  			return num(float64(p.fileLineNum))
   936  		case V_ARGC:
   937  			return num(float64(p.argc))
   938  		case V_CONVFMT:
   939  			return str(p.convertFormat)
   940  		case V_FILENAME:
   941  			return str(p.filename)
   942  		case V_FS:
   943  			return str(p.fieldSep)
   944  		case V_OFMT:
   945  			return str(p.outputFormat)
   946  		case V_OFS:
   947  			return str(p.outputFieldSep)
   948  		case V_ORS:
   949  			return str(p.outputRecordSep)
   950  		case V_RS:
   951  			return str(p.recordSep)
   952  		case V_SUBSEP:
   953  			return str(p.subscriptSep)
   954  		default:
   955  			panic(fmt.Sprintf("unexpected special variable index: %d", index))
   956  		}
   957  	}
   958  }
   959  
   960  // Set a variable by name (specials and globals only)
   961  func (p *interp) setVarByName(name, value string) error {
   962  	index := SpecialVarIndex(name)
   963  	if index > 0 {
   964  		return p.setVar(ScopeSpecial, index, numStr(value))
   965  	}
   966  	index, ok := p.program.Scalars[name]
   967  	if ok {
   968  		return p.setVar(ScopeGlobal, index, numStr(value))
   969  	}
   970  	// Ignore variables that aren't defined in program
   971  	return nil
   972  }
   973  
   974  // Set a variable by index in given scope to given value
   975  func (p *interp) setVar(scope VarScope, index int, v value) error {
   976  	switch scope {
   977  	case ScopeGlobal:
   978  		p.globals[index] = v
   979  		return nil
   980  	case ScopeLocal:
   981  		p.frame[index] = v
   982  		return nil
   983  	default: // ScopeSpecial
   984  		switch index {
   985  		case V_NF:
   986  			numFields := int(v.num())
   987  			if numFields < 0 {
   988  				return newError("NF set to negative value: %d", numFields)
   989  			}
   990  			if numFields > maxFieldIndex {
   991  				return newError("NF set too large: %d", numFields)
   992  			}
   993  			p.ensureFields()
   994  			p.numFields = numFields
   995  			if p.numFields < len(p.fields) {
   996  				p.fields = p.fields[:p.numFields]
   997  			}
   998  			for i := len(p.fields); i < p.numFields; i++ {
   999  				p.fields = append(p.fields, "")
  1000  			}
  1001  			p.line = strings.Join(p.fields, p.outputFieldSep)
  1002  		case V_NR:
  1003  			p.lineNum = int(v.num())
  1004  		case V_RLENGTH:
  1005  			p.matchLength = int(v.num())
  1006  		case V_RSTART:
  1007  			p.matchStart = int(v.num())
  1008  		case V_FNR:
  1009  			p.fileLineNum = int(v.num())
  1010  		case V_ARGC:
  1011  			p.argc = int(v.num())
  1012  		case V_CONVFMT:
  1013  			p.convertFormat = p.toString(v)
  1014  		case V_FILENAME:
  1015  			p.filename = p.toString(v)
  1016  		case V_FS:
  1017  			p.fieldSep = p.toString(v)
  1018  			if utf8.RuneCountInString(p.fieldSep) > 1 {
  1019  				re, err := regexp.Compile(p.fieldSep)
  1020  				if err != nil {
  1021  					return newError("invalid regex %q: %s", p.fieldSep, err)
  1022  				}
  1023  				p.fieldSepRegex = re
  1024  			}
  1025  		case V_OFMT:
  1026  			p.outputFormat = p.toString(v)
  1027  		case V_OFS:
  1028  			p.outputFieldSep = p.toString(v)
  1029  		case V_ORS:
  1030  			p.outputRecordSep = p.toString(v)
  1031  		case V_RS:
  1032  			sep := p.toString(v)
  1033  			if len(sep) > 1 {
  1034  				return newError("RS must be at most 1 char")
  1035  			}
  1036  			p.recordSep = sep
  1037  		case V_SUBSEP:
  1038  			p.subscriptSep = p.toString(v)
  1039  		default:
  1040  			panic(fmt.Sprintf("unexpected special variable index: %d", index))
  1041  		}
  1042  		return nil
  1043  	}
  1044  }
  1045  
  1046  // Determine the index of given array into the p.arrays slice. Global
  1047  // arrays are just at p.arrays[index], local arrays have to be looked
  1048  // up indirectly.
  1049  func (p *interp) getArrayIndex(scope VarScope, index int) int {
  1050  	if scope == ScopeGlobal {
  1051  		return index
  1052  	} else {
  1053  		return p.localArrays[len(p.localArrays)-1][index]
  1054  	}
  1055  }
  1056  
  1057  // Get a value from given array by key (index)
  1058  func (p *interp) getArrayValue(scope VarScope, arrayIndex int, index string) value {
  1059  	resolved := p.getArrayIndex(scope, arrayIndex)
  1060  	array := p.arrays[resolved]
  1061  	v, ok := array[index]
  1062  	if !ok {
  1063  		// Strangely, per the POSIX spec, "Any other reference to a
  1064  		// nonexistent array element [apart from "in" expressions]
  1065  		// shall automatically create it."
  1066  		array[index] = v
  1067  	}
  1068  	return v
  1069  }
  1070  
  1071  // Set a value in given array by key (index)
  1072  func (p *interp) setArrayValue(scope VarScope, arrayIndex int, index string, v value) {
  1073  	resolved := p.getArrayIndex(scope, arrayIndex)
  1074  	p.arrays[resolved][index] = v
  1075  }
  1076  
  1077  // Get the value of given numbered field, equivalent to "$index"
  1078  func (p *interp) getField(index int) (value, error) {
  1079  	if index < 0 {
  1080  		return null(), newError("field index negative: %d", index)
  1081  	}
  1082  	if index == 0 {
  1083  		return numStr(p.line), nil
  1084  	}
  1085  	p.ensureFields()
  1086  	if index > len(p.fields) {
  1087  		return str(""), nil
  1088  	}
  1089  	return numStr(p.fields[index-1]), nil
  1090  }
  1091  
  1092  // Sets a single field, equivalent to "$index = value"
  1093  func (p *interp) setField(index int, value string) error {
  1094  	if index == 0 {
  1095  		p.setLine(value)
  1096  		return nil
  1097  	}
  1098  	if index < 0 {
  1099  		return newError("field index negative: %d", index)
  1100  	}
  1101  	if index > maxFieldIndex {
  1102  		return newError("field index too large: %d", index)
  1103  	}
  1104  	// If there aren't enough fields, add empty string fields in between
  1105  	p.ensureFields()
  1106  	for i := len(p.fields); i < index; i++ {
  1107  		p.fields = append(p.fields, "")
  1108  	}
  1109  	p.fields[index-1] = value
  1110  	p.numFields = len(p.fields)
  1111  	p.line = strings.Join(p.fields, p.outputFieldSep)
  1112  	return nil
  1113  }
  1114  
  1115  // Convert value to string using current CONVFMT
  1116  func (p *interp) toString(v value) string {
  1117  	return v.str(p.convertFormat)
  1118  }
  1119  
  1120  // Compile regex string (or fetch from regex cache)
  1121  func (p *interp) compileRegex(regex string) (*regexp.Regexp, error) {
  1122  	if re, ok := p.regexCache[regex]; ok {
  1123  		return re, nil
  1124  	}
  1125  	re, err := regexp.Compile(regex)
  1126  	if err != nil {
  1127  		return nil, newError("invalid regex %q: %s", regex, err)
  1128  	}
  1129  	// Dumb, non-LRU cache: just cache the first N regexes
  1130  	if len(p.regexCache) < maxCachedRegexes {
  1131  		p.regexCache[regex] = re
  1132  	}
  1133  	return re, nil
  1134  }
  1135  
  1136  // Evaluate simple binary expression and return result
  1137  func (p *interp) evalBinary(op Token, l, r value) (value, error) {
  1138  	// Note: cases are ordered (very roughly) in order of frequency
  1139  	// of occurrence for performance reasons. Benchmark on common code
  1140  	// before changing the order.
  1141  	switch op {
  1142  	case ADD:
  1143  		return num(l.num() + r.num()), nil
  1144  	case SUB:
  1145  		return num(l.num() - r.num()), nil
  1146  	case EQUALS:
  1147  		if l.isTrueStr() || r.isTrueStr() {
  1148  			return boolean(p.toString(l) == p.toString(r)), nil
  1149  		} else {
  1150  			return boolean(l.n == r.n), nil
  1151  		}
  1152  	case LESS:
  1153  		if l.isTrueStr() || r.isTrueStr() {
  1154  			return boolean(p.toString(l) < p.toString(r)), nil
  1155  		} else {
  1156  			return boolean(l.n < r.n), nil
  1157  		}
  1158  	case LTE:
  1159  		if l.isTrueStr() || r.isTrueStr() {
  1160  			return boolean(p.toString(l) <= p.toString(r)), nil
  1161  		} else {
  1162  			return boolean(l.n <= r.n), nil
  1163  		}
  1164  	case CONCAT:
  1165  		return str(p.toString(l) + p.toString(r)), nil
  1166  	case MUL:
  1167  		return num(l.num() * r.num()), nil
  1168  	case DIV:
  1169  		rf := r.num()
  1170  		if rf == 0.0 {
  1171  			return null(), newError("division by zero")
  1172  		}
  1173  		return num(l.num() / rf), nil
  1174  	case GREATER:
  1175  		if l.isTrueStr() || r.isTrueStr() {
  1176  			return boolean(p.toString(l) > p.toString(r)), nil
  1177  		} else {
  1178  			return boolean(l.n > r.n), nil
  1179  		}
  1180  	case GTE:
  1181  		if l.isTrueStr() || r.isTrueStr() {
  1182  			return boolean(p.toString(l) >= p.toString(r)), nil
  1183  		} else {
  1184  			return boolean(l.n >= r.n), nil
  1185  		}
  1186  	case NOT_EQUALS:
  1187  		if l.isTrueStr() || r.isTrueStr() {
  1188  			return boolean(p.toString(l) != p.toString(r)), nil
  1189  		} else {
  1190  			return boolean(l.n != r.n), nil
  1191  		}
  1192  	case MATCH:
  1193  		re, err := p.compileRegex(p.toString(r))
  1194  		if err != nil {
  1195  			return null(), err
  1196  		}
  1197  		matched := re.MatchString(p.toString(l))
  1198  		return boolean(matched), nil
  1199  	case NOT_MATCH:
  1200  		re, err := p.compileRegex(p.toString(r))
  1201  		if err != nil {
  1202  			return null(), err
  1203  		}
  1204  		matched := re.MatchString(p.toString(l))
  1205  		return boolean(!matched), nil
  1206  	case POW:
  1207  		return num(math.Pow(l.num(), r.num())), nil
  1208  	case MOD:
  1209  		rf := r.num()
  1210  		if rf == 0.0 {
  1211  			return null(), newError("division by zero in mod")
  1212  		}
  1213  		return num(math.Mod(l.num(), rf)), nil
  1214  	default:
  1215  		panic(fmt.Sprintf("unexpected binary operation: %s", op))
  1216  	}
  1217  }
  1218  
  1219  // Evaluate unary expression and return result
  1220  func (p *interp) evalUnary(op Token, v value) value {
  1221  	switch op {
  1222  	case SUB:
  1223  		return num(-v.num())
  1224  	case NOT:
  1225  		return boolean(!v.boolean())
  1226  	case ADD:
  1227  		return num(v.num())
  1228  	default:
  1229  		panic(fmt.Sprintf("unexpected unary operation: %s", op))
  1230  	}
  1231  }
  1232  
  1233  // Perform an assignment: can assign to var, array[key], or $field
  1234  func (p *interp) assign(left Expr, right value) error {
  1235  	switch left := left.(type) {
  1236  	case *VarExpr:
  1237  		return p.setVar(left.Scope, left.Index, right)
  1238  	case *IndexExpr:
  1239  		index, err := p.evalIndex(left.Index)
  1240  		if err != nil {
  1241  			return err
  1242  		}
  1243  		p.setArrayValue(left.Array.Scope, left.Array.Index, index, right)
  1244  		return nil
  1245  	case *FieldExpr:
  1246  		index, err := p.eval(left.Index)
  1247  		if err != nil {
  1248  			return err
  1249  		}
  1250  		return p.setField(int(index.num()), p.toString(right))
  1251  	}
  1252  	// Shouldn't happen
  1253  	panic(fmt.Sprintf("unexpected lvalue type: %T", left))
  1254  }
  1255  
  1256  // Evaluate an index expression to a string. Multi-valued indexes are
  1257  // separated by SUBSEP.
  1258  func (p *interp) evalIndex(indexExprs []Expr) (string, error) {
  1259  	// Optimize the common case of a 1-dimensional index
  1260  	if len(indexExprs) == 1 {
  1261  		v, err := p.eval(indexExprs[0])
  1262  		if err != nil {
  1263  			return "", err
  1264  		}
  1265  		return p.toString(v), nil
  1266  	}
  1267  
  1268  	// Up to 3-dimensional indices won't require heap allocation
  1269  	indices := make([]string, 0, 3)
  1270  	for _, expr := range indexExprs {
  1271  		v, err := p.eval(expr)
  1272  		if err != nil {
  1273  			return "", err
  1274  		}
  1275  		indices = append(indices, p.toString(v))
  1276  	}
  1277  	return strings.Join(indices, p.subscriptSep), nil
  1278  }