1package gojq 2 3import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "sort" 9 "strconv" 10 "strings" 11) 12 13type compiler struct { 14 moduleLoader ModuleLoader 15 environLoader func() []string 16 variables []string 17 customFuncs map[string]function 18 inputIter Iter 19 codes []*code 20 codeinfos []codeinfo 21 scopes []*scopeinfo 22 scopecnt int 23} 24 25// Code is a compiled jq query. 26type Code struct { 27 variables []string 28 codes []*code 29 codeinfos []codeinfo 30} 31 32// Run runs the code with the variable values (which should be in the 33// same order as the given variables using WithVariables) and returns 34// a result iterator. 35// 36// It is safe to call this method of a *Code in multiple goroutines. 37func (c *Code) Run(v interface{}, values ...interface{}) Iter { 38 return c.RunWithContext(context.Background(), v, values...) 39} 40 41// RunWithContext runs the code with context. 42func (c *Code) RunWithContext(ctx context.Context, v interface{}, values ...interface{}) Iter { 43 if len(values) > len(c.variables) { 44 return NewIter(&tooManyVariableValuesError{}) 45 } else if len(values) < len(c.variables) { 46 return NewIter(&expectedVariableError{c.variables[len(values)]}) 47 } 48 for i, v := range values { 49 values[i] = normalizeNumbers(v) 50 } 51 return newEnv(ctx).execute(c, normalizeNumbers(v), values...) 52} 53 54// ModuleLoader is an interface for loading modules. 55// 56// Implement following optional methods. Use NewModuleLoader to load local modules. 57// LoadModule(string) (*Query, error) 58// LoadModuleWithMeta(string, map[string]interface{}) (*Query, error) 59// LoadInitModules() ([]*Query, error) 60// LoadJSON(string) (interface{}, error) 61// LoadJSONWithMeta(string, map[string]interface{}) (interface{}, error) 62type ModuleLoader interface{} 63 64type scopeinfo struct { 65 variables []*varinfo 66 funcs []*funcinfo 67 id int 68 depth int 69 variablecnt int 70} 71 72type varinfo struct { 73 name string 74 index [2]int 75 depth int 76} 77 78type funcinfo struct { 79 name string 80 pc int 81 argcnt int 82} 83 84// Compile compiles a query. 85func Compile(q *Query, options ...CompilerOption) (*Code, error) { 86 c := &compiler{} 87 for _, opt := range options { 88 opt(c) 89 } 90 scope := c.newScope() 91 c.scopes = []*scopeinfo{scope} 92 setscope := c.lazy(func() *code { 93 return &code{op: opscope, v: [3]int{scope.id, scope.variablecnt, 0}} 94 }) 95 if c.moduleLoader != nil { 96 if moduleLoader, ok := c.moduleLoader.(interface { 97 LoadInitModules() ([]*Query, error) 98 }); ok { 99 qs, err := moduleLoader.LoadInitModules() 100 if err != nil { 101 return nil, err 102 } 103 for _, q := range qs { 104 if err := c.compileModule(q, ""); err != nil { 105 return nil, err 106 } 107 } 108 } 109 } 110 if err := c.compile(q); err != nil { 111 return nil, err 112 } 113 setscope() 114 c.optimizeTailRec() 115 c.optimizeCodeOps() 116 return &Code{ 117 variables: c.variables, 118 codes: c.codes, 119 codeinfos: c.codeinfos, 120 }, nil 121} 122 123func (c *compiler) compile(q *Query) error { 124 for _, name := range c.variables { 125 if !newLexer(name).validVarName() { 126 return &variableNameError{name} 127 } 128 c.appendCodeInfo(name) 129 c.append(&code{op: opstore, v: c.pushVariable(name)}) 130 } 131 for _, i := range q.Imports { 132 if err := c.compileImport(i); err != nil { 133 return err 134 } 135 } 136 if err := c.compileQuery(q); err != nil { 137 return err 138 } 139 c.append(&code{op: opret}) 140 return nil 141} 142 143func (c *compiler) compileImport(i *Import) error { 144 var path, alias string 145 var err error 146 if i.ImportPath != "" { 147 path, alias = i.ImportPath, i.ImportAlias 148 } else { 149 path = i.IncludePath 150 } 151 if c.moduleLoader == nil { 152 return fmt.Errorf("cannot load module: %q", path) 153 } 154 if strings.HasPrefix(alias, "$") { 155 var vals interface{} 156 if moduleLoader, ok := c.moduleLoader.(interface { 157 LoadJSONWithMeta(string, map[string]interface{}) (interface{}, error) 158 }); ok { 159 if vals, err = moduleLoader.LoadJSONWithMeta(path, i.Meta.ToValue()); err != nil { 160 return err 161 } 162 } else if moduleLoader, ok := c.moduleLoader.(interface { 163 LoadJSON(string) (interface{}, error) 164 }); ok { 165 if vals, err = moduleLoader.LoadJSON(path); err != nil { 166 return err 167 } 168 } else { 169 return fmt.Errorf("module not found: %q", path) 170 } 171 vals = normalizeNumbers(vals) 172 c.append(&code{op: oppush, v: vals}) 173 c.append(&code{op: opstore, v: c.pushVariable(alias)}) 174 c.append(&code{op: oppush, v: vals}) 175 c.append(&code{op: opstore, v: c.pushVariable(alias + "::" + alias[1:])}) 176 return nil 177 } 178 var q *Query 179 if moduleLoader, ok := c.moduleLoader.(interface { 180 LoadModuleWithMeta(string, map[string]interface{}) (*Query, error) 181 }); ok { 182 if q, err = moduleLoader.LoadModuleWithMeta(path, i.Meta.ToValue()); err != nil { 183 return err 184 } 185 } else if moduleLoader, ok := c.moduleLoader.(interface { 186 LoadModule(string) (*Query, error) 187 }); ok { 188 if q, err = moduleLoader.LoadModule(path); err != nil { 189 return err 190 } 191 } 192 c.appendCodeInfo("module " + path) 193 defer c.appendCodeInfo("end of module " + path) 194 return c.compileModule(q, alias) 195} 196 197func (c *compiler) compileModule(q *Query, alias string) error { 198 scope := c.scopes[len(c.scopes)-1] 199 scope.depth++ 200 defer func(l int) { 201 scope.depth-- 202 scope.variables = scope.variables[:l] 203 }(len(scope.variables)) 204 if alias != "" { 205 defer func(l int) { 206 for _, f := range scope.funcs[l:] { 207 f.name = alias + "::" + f.name 208 } 209 }(len(scope.funcs)) 210 } 211 for _, i := range q.Imports { 212 if err := c.compileImport(i); err != nil { 213 return err 214 } 215 } 216 for _, fd := range q.FuncDefs { 217 if err := c.compileFuncDef(fd, false); err != nil { 218 return err 219 } 220 } 221 return nil 222} 223 224func (c *compiler) newVariable() [2]int { 225 return c.createVariable("") 226} 227 228func (c *compiler) pushVariable(name string) [2]int { 229 s := c.scopes[len(c.scopes)-1] 230 for _, v := range s.variables { 231 if v.name == name && v.depth == s.depth { 232 return v.index 233 } 234 } 235 return c.createVariable(name) 236} 237 238func (c *compiler) createVariable(name string) [2]int { 239 s := c.scopes[len(c.scopes)-1] 240 v := [2]int{s.id, s.variablecnt} 241 s.variablecnt++ 242 s.variables = append(s.variables, &varinfo{name, v, s.depth}) 243 return v 244} 245 246func (c *compiler) lookupVariable(name string) ([2]int, error) { 247 for i := len(c.scopes) - 1; i >= 0; i-- { 248 s := c.scopes[i] 249 for j := len(s.variables) - 1; j >= 0; j-- { 250 if w := s.variables[j]; w.name == name { 251 return w.index, nil 252 } 253 } 254 } 255 return [2]int{}, &variableNotFoundError{name} 256} 257 258func (c *compiler) lookupFuncOrVariable(name string) (*funcinfo, *varinfo) { 259 for i, isFunc := len(c.scopes)-1, name[0] != '$'; i >= 0; i-- { 260 s := c.scopes[i] 261 if isFunc { 262 for j := len(s.funcs) - 1; j >= 0; j-- { 263 if f := s.funcs[j]; f.name == name && f.argcnt == 0 { 264 return f, nil 265 } 266 } 267 } 268 for j := len(s.variables) - 1; j >= 0; j-- { 269 if v := s.variables[j]; v.name == name { 270 return nil, v 271 } 272 } 273 } 274 return nil, nil 275} 276 277func (c *compiler) newScope() *scopeinfo { 278 i := c.scopecnt // do not use len(c.scopes) because it pops 279 c.scopecnt++ 280 return &scopeinfo{id: i} 281} 282 283func (c *compiler) newScopeDepth() func() { 284 scope := c.scopes[len(c.scopes)-1] 285 l, m := len(scope.variables), len(scope.funcs) 286 scope.depth++ 287 return func() { 288 scope.depth-- 289 scope.variables = scope.variables[:l] 290 scope.funcs = scope.funcs[:m] 291 } 292} 293 294func (c *compiler) compileFuncDef(e *FuncDef, builtin bool) error { 295 var scope *scopeinfo 296 if builtin { 297 scope = c.scopes[0] 298 for i := len(scope.funcs) - 1; i >= 0; i-- { 299 if f := scope.funcs[i]; f.name == e.Name && f.argcnt == len(e.Args) { 300 return nil 301 } 302 } 303 } else { 304 scope = c.scopes[len(c.scopes)-1] 305 } 306 defer c.lazy(func() *code { 307 return &code{op: opjump, v: c.pc()} 308 })() 309 c.appendCodeInfo(e.Name) 310 defer c.appendCodeInfo("end of " + e.Name) 311 pc := c.pc() 312 scope.funcs = append(scope.funcs, &funcinfo{e.Name, pc, len(e.Args)}) 313 defer func(scopes []*scopeinfo, variables []string) { 314 c.scopes, c.variables = scopes, variables 315 }(c.scopes, c.variables) 316 c.variables = c.variables[len(c.variables):] 317 scope = c.newScope() 318 if builtin { 319 c.scopes = []*scopeinfo{c.scopes[0], scope} 320 } else { 321 c.scopes = append(c.scopes, scope) 322 } 323 defer c.lazy(func() *code { 324 return &code{op: opscope, v: [3]int{scope.id, scope.variablecnt, len(e.Args)}} 325 })() 326 if len(e.Args) > 0 { 327 type varIndex struct { 328 name string 329 index [2]int 330 } 331 vis := make([]varIndex, 0, len(e.Args)) 332 v := c.newVariable() 333 c.append(&code{op: opstore, v: v}) 334 for _, arg := range e.Args { 335 if arg[0] == '$' { 336 c.appendCodeInfo(arg[1:]) 337 w := c.createVariable(arg[1:]) 338 c.append(&code{op: opstore, v: w}) 339 vis = append(vis, varIndex{arg, w}) 340 } else { 341 c.appendCodeInfo(arg) 342 c.append(&code{op: opstore, v: c.createVariable(arg)}) 343 } 344 } 345 for _, w := range vis { 346 c.append(&code{op: opload, v: v}) 347 c.append(&code{op: opload, v: w.index}) 348 c.append(&code{op: opcallpc}) 349 c.appendCodeInfo(w.name) 350 c.append(&code{op: opstore, v: c.pushVariable(w.name)}) 351 } 352 c.append(&code{op: opload, v: v}) 353 } 354 return c.compile(e.Body) 355} 356 357func (c *compiler) compileQuery(e *Query) error { 358 for _, fd := range e.FuncDefs { 359 if err := c.compileFuncDef(fd, false); err != nil { 360 return err 361 } 362 } 363 if e.Func != "" { 364 switch e.Func { 365 case ".": 366 return c.compileTerm(&Term{Type: TermTypeIdentity}) 367 case "..": 368 return c.compileTerm(&Term{Type: TermTypeRecurse}) 369 case "null": 370 return c.compileTerm(&Term{Type: TermTypeNull}) 371 case "true": 372 return c.compileTerm(&Term{Type: TermTypeTrue}) 373 case "false": 374 return c.compileTerm(&Term{Type: TermTypeFalse}) 375 default: 376 return c.compileFunc(&Func{Name: e.Func}) 377 } 378 } else if e.Term != nil { 379 return c.compileTerm(e.Term) 380 } 381 switch e.Op { 382 case OpPipe: 383 if err := c.compileQuery(e.Left); err != nil { 384 return err 385 } 386 return c.compileQuery(e.Right) 387 case OpComma: 388 return c.compileComma(e.Left, e.Right) 389 case OpAlt: 390 return c.compileAlt(e.Left, e.Right) 391 case OpAssign, OpModify, OpUpdateAdd, OpUpdateSub, 392 OpUpdateMul, OpUpdateDiv, OpUpdateMod, OpUpdateAlt: 393 return c.compileQueryUpdate(e.Left, e.Right, e.Op) 394 case OpOr: 395 return c.compileIf( 396 &If{ 397 Cond: e.Left, 398 Then: &Query{Term: &Term{Type: TermTypeTrue}}, 399 Else: &Query{Term: &Term{Type: TermTypeIf, If: &If{ 400 Cond: e.Right, 401 Then: &Query{Term: &Term{Type: TermTypeTrue}}, 402 Else: &Query{Term: &Term{Type: TermTypeFalse}}, 403 }}}, 404 }, 405 ) 406 case OpAnd: 407 return c.compileIf( 408 &If{ 409 Cond: e.Left, 410 Then: &Query{Term: &Term{Type: TermTypeIf, If: &If{ 411 Cond: e.Right, 412 Then: &Query{Term: &Term{Type: TermTypeTrue}}, 413 Else: &Query{Term: &Term{Type: TermTypeFalse}}, 414 }}}, 415 Else: &Query{Term: &Term{Type: TermTypeFalse}}, 416 }, 417 ) 418 default: 419 return c.compileCall( 420 e.Op.getFunc(), 421 []*Query{e.Left, e.Right}, 422 ) 423 } 424} 425 426func (c *compiler) compileComma(l, r *Query) error { 427 setfork := c.lazy(func() *code { 428 return &code{op: opfork, v: c.pc() + 1} 429 }) 430 if err := c.compileQuery(l); err != nil { 431 return err 432 } 433 setfork() 434 defer c.lazy(func() *code { 435 return &code{op: opjump, v: c.pc()} 436 })() 437 return c.compileQuery(r) 438} 439 440func (c *compiler) compileAlt(l, r *Query) error { 441 c.append(&code{op: oppush, v: false}) 442 found := c.newVariable() 443 c.append(&code{op: opstore, v: found}) 444 setfork := c.lazy(func() *code { 445 return &code{op: opfork, v: c.pc()} // opload found 446 }) 447 if err := c.compileQuery(l); err != nil { 448 return err 449 } 450 c.append(&code{op: opdup}) 451 c.append(&code{op: opjumpifnot, v: c.pc() + 4}) // oppop 452 c.append(&code{op: oppush, v: true}) // found some value 453 c.append(&code{op: opstore, v: found}) 454 defer c.lazy(func() *code { 455 return &code{op: opjump, v: c.pc()} // ret 456 })() 457 c.append(&code{op: oppop}) 458 c.append(&code{op: opbacktrack}) 459 setfork() 460 c.append(&code{op: opload, v: found}) 461 c.append(&code{op: opjumpifnot, v: c.pc() + 3}) 462 c.append(&code{op: opbacktrack}) // if found, backtrack 463 c.append(&code{op: oppop}) 464 return c.compileQuery(r) 465} 466 467func (c *compiler) compileQueryUpdate(l, r *Query, op Operator) error { 468 switch op { 469 case OpAssign: 470 // .foo.bar = f => setpath(["foo", "bar"]; f) 471 if xs := l.toIndices(); xs != nil { 472 // ref: compileCall 473 v := c.newVariable() 474 c.append(&code{op: opstore, v: v}) 475 c.append(&code{op: opload, v: v}) 476 if err := c.compileQuery(r); err != nil { 477 return err 478 } 479 c.append(&code{op: oppush, v: xs}) 480 c.append(&code{op: opload, v: v}) 481 c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["setpath"].callback, 2, "setpath"}}) 482 return nil 483 } 484 fallthrough 485 case OpModify: 486 return c.compileFunc( 487 &Func{ 488 Name: op.getFunc(), 489 Args: []*Query{l, r}, 490 }, 491 ) 492 default: 493 name := "$%0" 494 c.append(&code{op: opdup}) 495 if err := c.compileQuery(r); err != nil { 496 return err 497 } 498 c.append(&code{op: opstore, v: c.pushVariable(name)}) 499 return c.compileFunc( 500 &Func{ 501 Name: "_modify", 502 Args: []*Query{ 503 l, 504 {Term: &Term{ 505 Type: TermTypeFunc, 506 Func: &Func{ 507 Name: op.getFunc(), 508 Args: []*Query{ 509 {Term: &Term{Type: TermTypeIdentity}}, 510 {Func: name}, 511 }, 512 }, 513 }}, 514 }, 515 }, 516 ) 517 } 518} 519 520func (c *compiler) compileBind(b *Bind) error { 521 var pc int 522 var vs [][2]int 523 for i, p := range b.Patterns { 524 var pcc int 525 var err error 526 if i < len(b.Patterns)-1 { 527 defer c.lazy(func() *code { 528 return &code{op: opforkalt, v: pcc} 529 })() 530 } 531 if 0 < i { 532 for _, v := range vs { 533 c.append(&code{op: oppush, v: nil}) 534 c.append(&code{op: opstore, v: v}) 535 } 536 } 537 vs, err = c.compilePattern(p) 538 if err != nil { 539 return err 540 } 541 if i < len(b.Patterns)-1 { 542 defer c.lazy(func() *code { 543 return &code{op: opjump, v: pc} 544 })() 545 pcc = c.pc() 546 } 547 } 548 if len(b.Patterns) > 1 { 549 pc = c.pc() 550 } 551 if len(b.Patterns) == 1 && c.codes[len(c.codes)-2].op == opexpbegin { 552 c.codes[len(c.codes)-2].op = opnop 553 } else { 554 c.append(&code{op: opexpend}) // ref: compileTermSuffix 555 } 556 return c.compileQuery(b.Body) 557} 558 559func (c *compiler) compilePattern(p *Pattern) ([][2]int, error) { 560 c.appendCodeInfo(p) 561 if p.Name != "" { 562 v := c.pushVariable(p.Name) 563 c.append(&code{op: opstore, v: v}) 564 return [][2]int{v}, nil 565 } else if len(p.Array) > 0 { 566 var vs [][2]int 567 v := c.newVariable() 568 c.append(&code{op: opstore, v: v}) 569 for i, p := range p.Array { 570 c.append(&code{op: oppush, v: i}) 571 c.append(&code{op: opload, v: v}) 572 c.append(&code{op: opload, v: v}) 573 // ref: compileCall 574 c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}}) 575 ns, err := c.compilePattern(p) 576 if err != nil { 577 return nil, err 578 } 579 vs = append(vs, ns...) 580 } 581 return vs, nil 582 } else if len(p.Object) > 0 { 583 var vs [][2]int 584 v := c.newVariable() 585 c.append(&code{op: opstore, v: v}) 586 for _, kv := range p.Object { 587 var key, name string 588 if kv.KeyOnly != "" { 589 key, name = kv.KeyOnly[1:], kv.KeyOnly 590 c.append(&code{op: oppush, v: key}) 591 } else if kv.Key != "" { 592 key = kv.Key 593 if key != "" && key[0] == '$' { 594 key, name = key[1:], key 595 } 596 c.append(&code{op: oppush, v: key}) 597 } else if kv.KeyString != nil { 598 c.append(&code{op: opload, v: v}) 599 if err := c.compileString(kv.KeyString, nil); err != nil { 600 return nil, err 601 } 602 } else if kv.KeyQuery != nil { 603 c.append(&code{op: opload, v: v}) 604 if err := c.compileQuery(kv.KeyQuery); err != nil { 605 return nil, err 606 } 607 } 608 c.append(&code{op: opload, v: v}) 609 c.append(&code{op: opload, v: v}) 610 // ref: compileCall 611 c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}}) 612 if name != "" { 613 if kv.Val != nil { 614 c.append(&code{op: opdup}) 615 } 616 ns, err := c.compilePattern(&Pattern{Name: name}) 617 if err != nil { 618 return nil, err 619 } 620 vs = append(vs, ns...) 621 } 622 if kv.Val != nil { 623 ns, err := c.compilePattern(kv.Val) 624 if err != nil { 625 return nil, err 626 } 627 vs = append(vs, ns...) 628 } 629 } 630 return vs, nil 631 } else { 632 return nil, fmt.Errorf("invalid pattern: %s", p) 633 } 634} 635 636func (c *compiler) compileIf(e *If) error { 637 c.appendCodeInfo(e) 638 c.append(&code{op: opdup}) // duplicate the value for then or else clause 639 c.append(&code{op: opexpbegin}) 640 pc := len(c.codes) 641 f := c.newScopeDepth() 642 if err := c.compileQuery(e.Cond); err != nil { 643 return err 644 } 645 f() 646 if pc == len(c.codes) { 647 c.codes = c.codes[:pc-1] 648 } else { 649 c.append(&code{op: opexpend}) 650 } 651 pcc := len(c.codes) 652 setjumpifnot := c.lazy(func() *code { 653 return &code{op: opjumpifnot, v: c.pc() + 1} // if falsy, skip then clause 654 }) 655 f = c.newScopeDepth() 656 if err := c.compileQuery(e.Then); err != nil { 657 return err 658 } 659 f() 660 setjumpifnot() 661 defer c.lazy(func() *code { 662 return &code{op: opjump, v: c.pc()} // jump to ret after else clause 663 })() 664 if len(e.Elif) > 0 { 665 return c.compileIf(&If{e.Elif[0].Cond, e.Elif[0].Then, e.Elif[1:], e.Else}) 666 } 667 if e.Else != nil { 668 defer c.newScopeDepth()() 669 defer func() { 670 // optimize constant results 671 // opdup, ..., opjumpifnot, opconst, opjump, opconst 672 // => opnop, ..., opjumpifnot, oppush, opjump, oppush 673 if pcc+4 == len(c.codes) && 674 c.codes[pcc+1] != nil && c.codes[pcc+1].op == opconst && 675 c.codes[pcc+3] != nil && c.codes[pcc+3].op == opconst { 676 c.codes[pc-2].op = opnop 677 c.codes[pcc+1].op = oppush 678 c.codes[pcc+3].op = oppush 679 } 680 }() 681 return c.compileQuery(e.Else) 682 } 683 return nil 684} 685 686func (c *compiler) compileTry(e *Try) error { 687 c.appendCodeInfo(e) 688 setforktrybegin := c.lazy(func() *code { 689 return &code{op: opforktrybegin, v: c.pc()} 690 }) 691 f := c.newScopeDepth() 692 if err := c.compileQuery(e.Body); err != nil { 693 return err 694 } 695 f() 696 c.append(&code{op: opforktryend}) 697 defer c.lazy(func() *code { 698 return &code{op: opjump, v: c.pc()} 699 })() 700 setforktrybegin() 701 if e.Catch != nil { 702 defer c.newScopeDepth()() 703 return c.compileQuery(e.Catch) 704 } 705 c.append(&code{op: opbacktrack}) 706 return nil 707} 708 709func (c *compiler) compileReduce(e *Reduce) error { 710 c.appendCodeInfo(e) 711 defer c.newScopeDepth()() 712 defer c.lazy(func() *code { 713 return &code{op: opfork, v: c.pc() - 2} 714 })() 715 c.append(&code{op: opdup}) 716 v := c.newVariable() 717 f := c.newScopeDepth() 718 if err := c.compileQuery(e.Start); err != nil { 719 return err 720 } 721 f() 722 c.append(&code{op: opstore, v: v}) 723 if err := c.compileTerm(e.Term); err != nil { 724 return err 725 } 726 if _, err := c.compilePattern(e.Pattern); err != nil { 727 return err 728 } 729 c.append(&code{op: opload, v: v}) 730 f = c.newScopeDepth() 731 if err := c.compileQuery(e.Update); err != nil { 732 return err 733 } 734 f() 735 c.append(&code{op: opstore, v: v}) 736 c.append(&code{op: opbacktrack}) 737 c.append(&code{op: oppop}) 738 c.append(&code{op: opload, v: v}) 739 return nil 740} 741 742func (c *compiler) compileForeach(e *Foreach) error { 743 c.appendCodeInfo(e) 744 defer c.newScopeDepth()() 745 c.append(&code{op: opdup}) 746 v := c.newVariable() 747 f := c.newScopeDepth() 748 if err := c.compileQuery(e.Start); err != nil { 749 return err 750 } 751 f() 752 c.append(&code{op: opstore, v: v}) 753 if err := c.compileTerm(e.Term); err != nil { 754 return err 755 } 756 if _, err := c.compilePattern(e.Pattern); err != nil { 757 return err 758 } 759 c.append(&code{op: opload, v: v}) 760 f = c.newScopeDepth() 761 if err := c.compileQuery(e.Update); err != nil { 762 return err 763 } 764 f() 765 c.append(&code{op: opdup}) 766 c.append(&code{op: opstore, v: v}) 767 if e.Extract != nil { 768 defer c.newScopeDepth()() 769 return c.compileQuery(e.Extract) 770 } 771 return nil 772} 773 774func (c *compiler) compileLabel(e *Label) error { 775 c.appendCodeInfo(e) 776 v := c.pushVariable("$%" + e.Ident[1:]) 777 defer c.lazy(func() *code { 778 return &code{op: opforklabel, v: v} 779 })() 780 return c.compileQuery(e.Body) 781} 782 783func (c *compiler) compileBreak(label string) error { 784 v, err := c.lookupVariable("$%" + label[1:]) 785 if err != nil { 786 return &breakError{label, nil} 787 } 788 c.append(&code{op: oppop}) 789 c.append(&code{op: opload, v: v}) 790 c.append(&code{op: opcall, v: [3]interface{}{ 791 func(v interface{}, _ []interface{}) interface{} { 792 return &breakError{label, v} 793 }, 794 0, 795 "_break", 796 }}) 797 return nil 798} 799 800func (c *compiler) compileTerm(e *Term) error { 801 if len(e.SuffixList) > 0 { 802 s := e.SuffixList[len(e.SuffixList)-1] 803 t := *e // clone without changing e 804 (&t).SuffixList = t.SuffixList[:len(e.SuffixList)-1] 805 return c.compileTermSuffix(&t, s) 806 } 807 switch e.Type { 808 case TermTypeIdentity: 809 return nil 810 case TermTypeRecurse: 811 return c.compileFunc(&Func{Name: "recurse"}) 812 case TermTypeNull: 813 c.append(&code{op: opconst, v: nil}) 814 return nil 815 case TermTypeTrue: 816 c.append(&code{op: opconst, v: true}) 817 return nil 818 case TermTypeFalse: 819 c.append(&code{op: opconst, v: false}) 820 return nil 821 case TermTypeIndex: 822 return c.compileIndex(&Term{Type: TermTypeIdentity}, e.Index) 823 case TermTypeFunc: 824 return c.compileFunc(e.Func) 825 case TermTypeObject: 826 return c.compileObject(e.Object) 827 case TermTypeArray: 828 return c.compileArray(e.Array) 829 case TermTypeNumber: 830 v := normalizeNumbers(json.Number(e.Number)) 831 if err, ok := v.(error); ok { 832 return err 833 } 834 c.append(&code{op: opconst, v: v}) 835 return nil 836 case TermTypeUnary: 837 return c.compileUnary(e.Unary) 838 case TermTypeFormat: 839 return c.compileFormat(e.Format, e.Str) 840 case TermTypeString: 841 return c.compileString(e.Str, nil) 842 case TermTypeIf: 843 return c.compileIf(e.If) 844 case TermTypeTry: 845 return c.compileTry(e.Try) 846 case TermTypeReduce: 847 return c.compileReduce(e.Reduce) 848 case TermTypeForeach: 849 return c.compileForeach(e.Foreach) 850 case TermTypeLabel: 851 return c.compileLabel(e.Label) 852 case TermTypeBreak: 853 return c.compileBreak(e.Break) 854 case TermTypeQuery: 855 defer c.newScopeDepth()() 856 return c.compileQuery(e.Query) 857 default: 858 panic("invalid term: " + e.String()) 859 } 860} 861 862func (c *compiler) compileIndex(e *Term, x *Index) error { 863 c.appendCodeInfo(x) 864 if x.Name != "" { 865 return c.compileCall("_index", []*Query{{Term: e}, {Term: &Term{Type: TermTypeString, Str: &String{Str: x.Name}}}}) 866 } 867 if x.Str != nil { 868 return c.compileCall("_index", []*Query{{Term: e}, {Term: &Term{Type: TermTypeString, Str: x.Str}}}) 869 } 870 if !x.IsSlice { 871 return c.compileCall("_index", []*Query{{Term: e}, x.Start}) 872 } 873 if x.Start == nil { 874 return c.compileCall("_slice", []*Query{{Term: e}, x.End, {Term: &Term{Type: TermTypeNull}}}) 875 } 876 if x.End == nil { 877 return c.compileCall("_slice", []*Query{{Term: e}, {Term: &Term{Type: TermTypeNull}}, x.Start}) 878 } 879 return c.compileCall("_slice", []*Query{{Term: e}, x.End, x.Start}) 880} 881 882func (c *compiler) compileFunc(e *Func) error { 883 name := e.Name 884 if len(e.Args) == 0 { 885 if f, v := c.lookupFuncOrVariable(name); f != nil { 886 return c.compileCallPc(f, e.Args) 887 } else if v != nil { 888 if name[0] == '$' { 889 c.append(&code{op: oppop}) 890 c.append(&code{op: opload, v: v.index}) 891 } else { 892 c.append(&code{op: opload, v: v.index}) 893 c.append(&code{op: opcallpc}) 894 } 895 return nil 896 } else if name == "$ENV" || name == "env" { 897 env := make(map[string]interface{}) 898 if c.environLoader != nil { 899 for _, kv := range c.environLoader() { 900 if i := strings.IndexByte(kv, '='); i > 0 { 901 env[kv[:i]] = kv[i+1:] 902 } 903 } 904 } 905 c.append(&code{op: opconst, v: env}) 906 return nil 907 } else if name[0] == '$' { 908 return &variableNotFoundError{name} 909 } 910 } else { 911 for i := len(c.scopes) - 1; i >= 0; i-- { 912 s := c.scopes[i] 913 for j := len(s.funcs) - 1; j >= 0; j-- { 914 if f := s.funcs[j]; f.name == name && f.argcnt == len(e.Args) { 915 return c.compileCallPc(f, e.Args) 916 } 917 } 918 } 919 } 920 if name[0] == '_' { 921 name = name[1:] 922 } 923 if fds, ok := builtinFuncDefs[name]; ok { 924 for _, fd := range fds { 925 if len(fd.Args) == len(e.Args) { 926 if err := c.compileFuncDef(fd, true); err != nil { 927 return err 928 } 929 } 930 } 931 s := c.scopes[0] 932 for i := len(s.funcs) - 1; i >= 0; i-- { 933 if f := s.funcs[i]; f.name == e.Name && f.argcnt == len(e.Args) { 934 return c.compileCallPc(f, e.Args) 935 } 936 } 937 } 938 if fn, ok := internalFuncs[e.Name]; ok && fn.accept(len(e.Args)) { 939 switch e.Name { 940 case "empty": 941 c.append(&code{op: opbacktrack}) 942 return nil 943 case "path": 944 c.append(&code{op: oppathbegin}) 945 if err := c.compileCall(e.Name, e.Args); err != nil { 946 return err 947 } 948 c.codes[len(c.codes)-1] = &code{op: oppathend} 949 return nil 950 case "builtins": 951 return c.compileCallInternal( 952 [3]interface{}{c.funcBuiltins, 0, e.Name}, 953 e.Args, 954 true, 955 false, 956 ) 957 case "scope": 958 return c.compileCallInternal( 959 [3]interface{}{c.funcScope, 0, e.Name}, 960 e.Args, 961 true, 962 false, 963 ) 964 case "input": 965 if c.inputIter == nil { 966 return &inputNotAllowedError{} 967 } 968 return c.compileCallInternal( 969 [3]interface{}{c.funcInput, 0, e.Name}, 970 e.Args, 971 true, 972 false, 973 ) 974 case "modulemeta": 975 return c.compileCallInternal( 976 [3]interface{}{c.funcModulemeta, 0, e.Name}, 977 e.Args, 978 true, 979 false, 980 ) 981 case "scopedump": 982 c.append(&code{op: oppop}) 983 n := 0 984 for i := len(c.scopes) - 1; i >= 0; i-- { 985 s := c.scopes[i] 986 for j := len(s.variables) - 1; j >= 0; j-- { 987 v := s.variables[j] 988 c.append(&code{op: oppush, v: v.name}) 989 c.append(&code{op: opload, v: v.index}) 990 n++ 991 } 992 } 993 c.append(&code{op: opobject, v: n}) 994 return nil 995 default: 996 return c.compileCall(e.Name, e.Args) 997 } 998 } 999 if fn, ok := c.customFuncs[e.Name]; ok && fn.accept(len(e.Args)) { 1000 if err := c.compileCallInternal( 1001 [3]interface{}{fn.callback, len(e.Args), e.Name}, 1002 e.Args, 1003 true, 1004 false, 1005 ); err != nil { 1006 return err 1007 } 1008 if fn.iter { 1009 c.append(&code{op: opeach}) 1010 } 1011 return nil 1012 } 1013 return &funcNotFoundError{e} 1014} 1015 1016func (c *compiler) funcBuiltins(interface{}, []interface{}) interface{} { 1017 type funcNameArity struct { 1018 name string 1019 arity int 1020 } 1021 var xs []*funcNameArity 1022 for _, fds := range builtinFuncDefs { 1023 for _, fd := range fds { 1024 if fd.Name[0] != '_' { 1025 xs = append(xs, &funcNameArity{fd.Name, len(fd.Args)}) 1026 } 1027 } 1028 } 1029 for name, fn := range internalFuncs { 1030 if name[0] != '_' { 1031 for i, cnt := 0, fn.argcount; cnt > 0; i, cnt = i+1, cnt>>1 { 1032 if cnt&1 > 0 { 1033 xs = append(xs, &funcNameArity{name, i}) 1034 } 1035 } 1036 } 1037 } 1038 for name, fn := range c.customFuncs { 1039 if name[0] != '_' { 1040 for i, cnt := 0, fn.argcount; cnt > 0; i, cnt = i+1, cnt>>1 { 1041 if cnt&1 > 0 { 1042 xs = append(xs, &funcNameArity{name, i}) 1043 } 1044 } 1045 } 1046 } 1047 sort.Slice(xs, func(i, j int) bool { 1048 return xs[i].name < xs[j].name || 1049 xs[i].name == xs[j].name && xs[i].arity < xs[j].arity 1050 }) 1051 ys := make([]interface{}, len(xs)) 1052 for i, x := range xs { 1053 ys[i] = x.name + "/" + strconv.Itoa(x.arity) 1054 } 1055 return ys 1056} 1057 1058func (c *compiler) funcScope(interface{}, []interface{}) interface{} { 1059 var xs []interface{} 1060 for _, fds := range builtinFuncDefs { 1061 xs = append(xs, fds[0].Name) 1062 } 1063 for name := range internalFuncs { 1064 xs = append(xs, name) 1065 } 1066 for name := range c.customFuncs { 1067 xs = append(xs, name) 1068 } 1069 if c.environLoader != nil { 1070 xs = append(xs, "$ENV") 1071 } 1072 for i := len(c.scopes) - 1; i >= 0; i-- { 1073 s := c.scopes[i] 1074 for j := len(s.variables) - 1; j >= 0; j-- { 1075 v := s.variables[j] 1076 xs = append(xs, v.name) 1077 } 1078 for j := len(s.funcs) - 1; j >= 0; j-- { 1079 f := s.funcs[j] 1080 xs = append(xs, f.name) 1081 } 1082 } 1083 sort.Slice(xs, func(i, j int) bool { 1084 return xs[i].(string) < xs[j].(string) 1085 }) 1086 return xs 1087} 1088 1089func (c *compiler) funcInput(interface{}, []interface{}) interface{} { 1090 v, ok := c.inputIter.Next() 1091 if !ok { 1092 return errors.New("break") 1093 } 1094 return normalizeNumbers(v) 1095} 1096 1097func (c *compiler) funcModulemeta(v interface{}, _ []interface{}) interface{} { 1098 s, ok := v.(string) 1099 if !ok { 1100 return &funcTypeError{"modulemeta", v} 1101 } 1102 if c.moduleLoader == nil { 1103 return fmt.Errorf("cannot load module: %q", s) 1104 } 1105 var q *Query 1106 var err error 1107 if moduleLoader, ok := c.moduleLoader.(interface { 1108 LoadModuleWithMeta(string, map[string]interface{}) (*Query, error) 1109 }); ok { 1110 if q, err = moduleLoader.LoadModuleWithMeta(s, nil); err != nil { 1111 return err 1112 } 1113 } else if moduleLoader, ok := c.moduleLoader.(interface { 1114 LoadModule(string) (*Query, error) 1115 }); ok { 1116 if q, err = moduleLoader.LoadModule(s); err != nil { 1117 return err 1118 } 1119 } 1120 meta := q.Meta.ToValue() 1121 if meta == nil { 1122 meta = make(map[string]interface{}) 1123 } 1124 var deps []interface{} 1125 for _, i := range q.Imports { 1126 v := i.Meta.ToValue() 1127 if v == nil { 1128 v = make(map[string]interface{}) 1129 } else { 1130 for k := range v { 1131 // dirty hack to remove the internal fields 1132 if strings.HasPrefix(k, "$$") { 1133 delete(v, k) 1134 } 1135 } 1136 } 1137 if i.ImportPath == "" { 1138 v["relpath"] = i.IncludePath 1139 } else { 1140 v["relpath"] = i.ImportPath 1141 } 1142 if err != nil { 1143 return err 1144 } 1145 if i.ImportAlias != "" { 1146 v["as"] = strings.TrimPrefix(i.ImportAlias, "$") 1147 } 1148 v["is_data"] = strings.HasPrefix(i.ImportAlias, "$") 1149 deps = append(deps, v) 1150 } 1151 meta["deps"] = deps 1152 return meta 1153} 1154 1155func (c *compiler) compileObject(e *Object) error { 1156 c.appendCodeInfo(e) 1157 if len(e.KeyVals) == 0 { 1158 c.append(&code{op: opconst, v: map[string]interface{}{}}) 1159 return nil 1160 } 1161 defer c.newScopeDepth()() 1162 v := c.newVariable() 1163 c.append(&code{op: opstore, v: v}) 1164 pc := len(c.codes) 1165 for _, kv := range e.KeyVals { 1166 if err := c.compileObjectKeyVal(v, kv); err != nil { 1167 return err 1168 } 1169 } 1170 c.append(&code{op: opobject, v: len(e.KeyVals)}) 1171 // optimize constant objects 1172 l := len(e.KeyVals) 1173 if pc+l*3+1 != len(c.codes) { 1174 return nil 1175 } 1176 for i := 0; i < l; i++ { 1177 if c.codes[pc+i*3].op != oppush || 1178 c.codes[pc+i*3+1].op != opload || 1179 c.codes[pc+i*3+2].op != opconst { 1180 return nil 1181 } 1182 } 1183 w := make(map[string]interface{}, l) 1184 for i := 0; i < l; i++ { 1185 w[c.codes[pc+i*3].v.(string)] = c.codes[pc+i*3+2].v 1186 } 1187 c.codes[pc-1] = &code{op: opconst, v: w} 1188 c.codes = c.codes[:pc] 1189 return nil 1190} 1191 1192func (c *compiler) compileObjectKeyVal(v [2]int, kv *ObjectKeyVal) error { 1193 if kv.KeyOnly != "" { 1194 if kv.KeyOnly[0] == '$' { 1195 c.append(&code{op: oppush, v: kv.KeyOnly[1:]}) 1196 c.append(&code{op: opload, v: v}) 1197 return c.compileFunc(&Func{Name: kv.KeyOnly}) 1198 } 1199 c.append(&code{op: oppush, v: kv.KeyOnly}) 1200 c.append(&code{op: opload, v: v}) 1201 return c.compileIndex(&Term{Type: TermTypeIdentity}, &Index{Name: kv.KeyOnly}) 1202 } else if kv.KeyOnlyString != nil { 1203 c.append(&code{op: opload, v: v}) 1204 if err := c.compileString(kv.KeyOnlyString, nil); err != nil { 1205 return err 1206 } 1207 c.append(&code{op: opdup}) 1208 c.append(&code{op: opload, v: v}) 1209 c.append(&code{op: opload, v: v}) 1210 // ref: compileCall 1211 c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}}) 1212 return nil 1213 } else { 1214 if kv.KeyQuery != nil { 1215 c.append(&code{op: opload, v: v}) 1216 f := c.newScopeDepth() 1217 if err := c.compileQuery(kv.KeyQuery); err != nil { 1218 return err 1219 } 1220 f() 1221 } else if kv.KeyString != nil { 1222 c.append(&code{op: opload, v: v}) 1223 if err := c.compileString(kv.KeyString, nil); err != nil { 1224 return err 1225 } 1226 if d := c.codes[len(c.codes)-1]; d.op == opconst { 1227 c.codes[len(c.codes)-2] = &code{op: oppush, v: d.v} 1228 c.codes = c.codes[:len(c.codes)-1] 1229 } 1230 } else if kv.Key[0] == '$' { 1231 c.append(&code{op: opload, v: v}) 1232 if err := c.compileFunc(&Func{Name: kv.Key}); err != nil { 1233 return err 1234 } 1235 } else { 1236 c.append(&code{op: oppush, v: kv.Key}) 1237 } 1238 c.append(&code{op: opload, v: v}) 1239 return c.compileObjectVal(kv.Val) 1240 } 1241} 1242 1243func (c *compiler) compileObjectVal(e *ObjectVal) error { 1244 for _, e := range e.Queries { 1245 if err := c.compileQuery(e); err != nil { 1246 return err 1247 } 1248 } 1249 return nil 1250} 1251 1252func (c *compiler) compileArray(e *Array) error { 1253 c.appendCodeInfo(e) 1254 if e.Query == nil { 1255 c.append(&code{op: opconst, v: []interface{}{}}) 1256 return nil 1257 } 1258 c.append(&code{op: oppush, v: []interface{}{}}) 1259 arr := c.newVariable() 1260 c.append(&code{op: opstore, v: arr}) 1261 pc := len(c.codes) 1262 c.append(&code{op: opfork}) 1263 defer func() { 1264 if pc < len(c.codes) { 1265 c.codes[pc].v = c.pc() - 2 1266 } 1267 }() 1268 defer c.newScopeDepth()() 1269 if err := c.compileQuery(e.Query); err != nil { 1270 return err 1271 } 1272 c.append(&code{op: opappend, v: arr}) 1273 c.append(&code{op: opbacktrack}) 1274 c.append(&code{op: oppop}) 1275 c.append(&code{op: opload, v: arr}) 1276 if e.Query.Op == OpPipe { 1277 return nil 1278 } 1279 // optimize constant arrays 1280 if (len(c.codes)-pc)%3 != 0 { 1281 return nil 1282 } 1283 l := (len(c.codes) - pc - 3) / 3 1284 for i := 0; i < l; i++ { 1285 if c.codes[pc+i].op != opfork || 1286 c.codes[pc+i*2+l].op != opconst || 1287 (i < l-1 && c.codes[pc+i*2+l+1].op != opjump) { 1288 return nil 1289 } 1290 } 1291 v := make([]interface{}, l) 1292 for i := 0; i < l; i++ { 1293 v[i] = c.codes[pc+i*2+l].v 1294 } 1295 c.codes[pc-2] = &code{op: opconst, v: v} 1296 c.codes = c.codes[:pc-1] 1297 return nil 1298} 1299 1300func (c *compiler) compileUnary(e *Unary) error { 1301 c.appendCodeInfo(e) 1302 if err := c.compileTerm(e.Term); err != nil { 1303 return err 1304 } 1305 switch e.Op { 1306 case OpAdd: 1307 return c.compileCall("_plus", nil) 1308 case OpSub: 1309 return c.compileCall("_negate", nil) 1310 case OpBnot: 1311 return c.compileCall("_bnot", nil) 1312 default: 1313 return fmt.Errorf("unexpected operator in Unary: %s", e.Op) 1314 } 1315} 1316 1317func (c *compiler) compileFormat(fmt string, str *String) error { 1318 f := formatToFunc(fmt) 1319 if f == nil { 1320 f = &Func{ 1321 Name: "format", 1322 Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: fmt[1:]}}}}, 1323 } 1324 } 1325 if str == nil { 1326 return c.compileFunc(f) 1327 } 1328 return c.compileString(str, f) 1329} 1330 1331func formatToFunc(fmt string) *Func { 1332 switch fmt { 1333 case "@text": 1334 return &Func{Name: "tostring"} 1335 case "@json": 1336 return &Func{Name: "tojson"} 1337 case "@html": 1338 return &Func{Name: "_tohtml"} 1339 case "@uri": 1340 return &Func{Name: "_touri"} 1341 case "@csv": 1342 return &Func{Name: "_tocsv"} 1343 case "@tsv": 1344 return &Func{Name: "_totsv"} 1345 case "@sh": 1346 return &Func{Name: "_tosh"} 1347 case "@base64": 1348 return &Func{Name: "_tobase64"} 1349 case "@base64d": 1350 return &Func{Name: "_tobase64d"} 1351 default: 1352 return nil 1353 } 1354} 1355 1356func (c *compiler) compileString(s *String, f *Func) error { 1357 if s.Queries == nil { 1358 c.append(&code{op: opconst, v: s.Str}) 1359 return nil 1360 } 1361 if f == nil { 1362 f = &Func{Name: "tostring"} 1363 } 1364 var q *Query 1365 for _, e := range s.Queries { 1366 if e.Term.Str == nil { 1367 e = &Query{Left: e, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: f}}} 1368 } 1369 if q == nil { 1370 q = e 1371 } else { 1372 q = &Query{Left: q, Op: OpAdd, Right: e} 1373 } 1374 } 1375 return c.compileQuery(q) 1376} 1377 1378func (c *compiler) compileTermSuffix(e *Term, s *Suffix) error { 1379 if s.Index != nil { 1380 return c.compileIndex(e, s.Index) 1381 } else if s.Iter { 1382 if err := c.compileTerm(e); err != nil { 1383 return err 1384 } 1385 c.append(&code{op: opeach}) 1386 return nil 1387 } else if s.Optional { 1388 if len(e.SuffixList) > 1 || len(e.SuffixList) == 1 && !e.SuffixList[0].Iter { 1389 if u, ok := e.SuffixList[len(e.SuffixList)-1].toTerm(); ok { 1390 t := *e // clone without changing e 1391 (&t).SuffixList = t.SuffixList[:len(e.SuffixList)-1] 1392 if err := c.compileTerm(&t); err != nil { 1393 return err 1394 } 1395 return c.compileTermSuffix(u, s) 1396 } 1397 } 1398 return c.compileTry(&Try{Body: &Query{Term: e}}) 1399 } else if s.Bind != nil { 1400 c.append(&code{op: opdup}) 1401 c.append(&code{op: opexpbegin}) 1402 if err := c.compileTerm(e); err != nil { 1403 return err 1404 } 1405 return c.compileBind(s.Bind) 1406 } else { 1407 return fmt.Errorf("invalid suffix: %s", s) 1408 } 1409} 1410 1411func (c *compiler) compileCall(name string, args []*Query) error { 1412 fn := internalFuncs[name] 1413 if err := c.compileCallInternal( 1414 [3]interface{}{fn.callback, len(args), name}, 1415 args, 1416 true, 1417 name == "_index" || name == "_slice", 1418 ); err != nil { 1419 return err 1420 } 1421 if fn.iter { 1422 c.append(&code{op: opeach}) 1423 } 1424 return nil 1425} 1426 1427func (c *compiler) compileCallPc(fn *funcinfo, args []*Query) error { 1428 return c.compileCallInternal(fn.pc, args, false, false) 1429} 1430 1431func (c *compiler) compileCallInternal( 1432 fn interface{}, args []*Query, internal, indexing bool) error { 1433 if len(args) == 0 { 1434 c.append(&code{op: opcall, v: fn}) 1435 return nil 1436 } 1437 idx := c.newVariable() 1438 c.append(&code{op: opstore, v: idx}) 1439 if indexing && len(args) > 1 { 1440 c.append(&code{op: opexpbegin}) 1441 } 1442 for i := len(args) - 1; i >= 0; i-- { 1443 pc := c.pc() + 1 // skip opjump (ref: compileFuncDef) 1444 name := "lambda:" + strconv.Itoa(pc) 1445 if err := c.compileFuncDef(&FuncDef{Name: name, Body: args[i]}, false); err != nil { 1446 return err 1447 } 1448 if internal { 1449 switch c.pc() - pc { 1450 case 2: // optimize identity argument (opscope, opret) 1451 j := len(c.codes) - 3 1452 c.codes[j] = &code{op: opload, v: idx} 1453 c.codes = c.codes[:j+1] 1454 s := c.scopes[len(c.scopes)-1] 1455 s.funcs = s.funcs[:len(s.funcs)-1] 1456 c.deleteCodeInfo(name) 1457 case 3: // optimize one instruction argument (opscope, opX, opret) 1458 j := len(c.codes) - 4 1459 if c.codes[j+2].op == opconst { 1460 c.codes[j] = &code{op: oppush, v: c.codes[j+2].v} 1461 c.codes = c.codes[:j+1] 1462 } else { 1463 c.codes[j] = &code{op: opload, v: idx} 1464 c.codes[j+1] = c.codes[j+2] 1465 c.codes = c.codes[:j+2] 1466 } 1467 s := c.scopes[len(c.scopes)-1] 1468 s.funcs = s.funcs[:len(s.funcs)-1] 1469 c.deleteCodeInfo(name) 1470 default: 1471 c.append(&code{op: opload, v: idx}) 1472 c.append(&code{op: oppushpc, v: pc}) 1473 c.append(&code{op: opcallpc}) 1474 } 1475 } else { 1476 c.append(&code{op: oppushpc, v: pc}) 1477 } 1478 if indexing && i == 1 { 1479 if c.codes[len(c.codes)-2].op == opexpbegin { 1480 c.codes[len(c.codes)-2] = c.codes[len(c.codes)-1] 1481 c.codes = c.codes[:len(c.codes)-1] 1482 } else { 1483 c.append(&code{op: opexpend}) 1484 } 1485 } 1486 } 1487 c.append(&code{op: opload, v: idx}) 1488 c.append(&code{op: opcall, v: fn}) 1489 return nil 1490} 1491 1492func (c *compiler) append(code *code) { 1493 c.codes = append(c.codes, code) 1494} 1495 1496func (c *compiler) pc() int { 1497 return len(c.codes) 1498} 1499 1500func (c *compiler) lazy(f func() *code) func() { 1501 i := len(c.codes) 1502 c.codes = append(c.codes, nil) 1503 return func() { c.codes[i] = f() } 1504} 1505 1506func (c *compiler) optimizeTailRec() { 1507 var pcs []int 1508 scopes := map[int]bool{} 1509L: 1510 for i, l := 0, len(c.codes); i < l; i++ { 1511 switch c.codes[i].op { 1512 case opscope: 1513 pcs = append(pcs, i) 1514 if v := c.codes[i].v.([3]int); v[2] == 0 { 1515 scopes[i] = v[1] == 0 1516 } 1517 case opcall: 1518 var canjump bool 1519 if j, ok := c.codes[i].v.(int); !ok || 1520 len(pcs) == 0 || pcs[len(pcs)-1] != j { 1521 break 1522 } else if canjump, ok = scopes[j]; !ok { 1523 break 1524 } 1525 for j := i + 1; j < l; { 1526 switch c.codes[j].op { 1527 case opjump: 1528 j = c.codes[j].v.(int) 1529 case opret: 1530 if canjump { 1531 c.codes[i].op = opjump 1532 c.codes[i].v = pcs[len(pcs)-1] + 1 1533 } else { 1534 c.codes[i].op = opcallrec 1535 } 1536 continue L 1537 default: 1538 continue L 1539 } 1540 } 1541 case opret: 1542 if len(pcs) == 0 { 1543 break L 1544 } 1545 pcs = pcs[:len(pcs)-1] 1546 } 1547 } 1548} 1549 1550func (c *compiler) optimizeCodeOps() { 1551 for i, next := len(c.codes)-1, (*code)(nil); i >= 0; i-- { 1552 code := c.codes[i] 1553 switch code.op { 1554 case oppush, opdup, opload: 1555 switch next.op { 1556 case oppop: 1557 code.op = opnop 1558 next.op = opnop 1559 case opconst: 1560 code.op = opnop 1561 next.op = oppush 1562 } 1563 case opjump, opjumpifnot: 1564 if j := code.v.(int); j-1 == i { 1565 code.op = opnop 1566 } else if next = c.codes[j]; next.op == opjump { 1567 code.v = next.v 1568 } 1569 } 1570 next = code 1571 } 1572} 1573