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 }