github.com/shawnclovie/gopher-lua@v0.0.0-20200520092726-90b44ec0e2f2/compile.go (about) 1 package lua 2 3 import ( 4 "fmt" 5 "math" 6 "reflect" 7 8 "github.com/shawnclovie/gopher-lua/ast" 9 ) 10 11 /* internal constants & structs {{{ */ 12 13 const maxRegisters = 200 14 15 type expContextType int 16 17 const ( 18 ecGlobal expContextType = iota 19 ecUpvalue 20 ecLocal 21 ecTable 22 ecVararg 23 ecMethod 24 ecNone 25 ) 26 27 const regNotDefined = opMaxArgsA + 1 28 const labelNoJump = 0 29 30 type expcontext struct { 31 ctype expContextType 32 reg int 33 // varargopt >= 0: wants varargopt+1 results, i.e a = func() 34 // varargopt = -1: ignore results i.e func() 35 // varargopt = -2: receive all results i.e a = {func()} 36 varargopt int 37 } 38 39 type assigncontext struct { 40 ec *expcontext 41 keyrk int 42 valuerk int 43 keyks bool 44 needmove bool 45 } 46 47 type lblabels struct { 48 t int 49 f int 50 e int 51 b bool 52 } 53 54 type constLValueExpr struct { 55 ast.ExprBase 56 57 Value LValue 58 } 59 60 // }}} 61 62 /* utilities {{{ */ 63 var _ecnone0 = &expcontext{ecNone, regNotDefined, 0} 64 var _ecnonem1 = &expcontext{ecNone, regNotDefined, -1} 65 var _ecnonem2 = &expcontext{ecNone, regNotDefined, -2} 66 var ecfuncdef = &expcontext{ecMethod, regNotDefined, 0} 67 68 func ecupdate(ec *expcontext, ctype expContextType, reg, varargopt int) { 69 if ec == _ecnone0 || ec == _ecnonem1 || ec == _ecnonem2 { 70 panic("can not update ec cache") 71 } 72 ec.ctype = ctype 73 ec.reg = reg 74 ec.varargopt = varargopt 75 } 76 77 func ecnone(varargopt int) *expcontext { 78 switch varargopt { 79 case 0: 80 return _ecnone0 81 case -1: 82 return _ecnonem1 83 case -2: 84 return _ecnonem2 85 } 86 return &expcontext{ecNone, regNotDefined, varargopt} 87 } 88 89 func shouldmove(ec *expcontext, reg int) bool { 90 return ec.ctype == ecLocal && ec.reg != regNotDefined && ec.reg != reg 91 } 92 93 func sline(pos ast.PositionHolder) int { 94 return pos.Line() 95 } 96 97 func eline(pos ast.PositionHolder) int { 98 return pos.LastLine() 99 } 100 101 func savereg(ec *expcontext, reg int) int { 102 if ec.ctype != ecLocal || ec.reg == regNotDefined { 103 return reg 104 } 105 return ec.reg 106 } 107 108 func raiseCompileError(context *funcContext, line int, format string, args ...interface{}) { 109 msg := fmt.Sprintf(format, args...) 110 panic(&CompileError{context: context, Line: line, Message: msg}) 111 } 112 113 func isVarArgReturnExpr(expr ast.Expr) bool { 114 switch ex := expr.(type) { 115 case *ast.FuncCallExpr: 116 return !ex.AdjustRet 117 case *ast.Comma3Expr: 118 return true 119 } 120 return false 121 } 122 123 func lnumberValue(expr ast.Expr) (LNumber, bool) { 124 if ex, ok := expr.(*ast.NumberExpr); ok { 125 lv, err := parseNumber(ex.Value) 126 if err != nil { 127 lv = LNumber(math.NaN()) 128 } 129 return lv, true 130 } else if ex, ok := expr.(*constLValueExpr); ok { 131 return ex.Value.(LNumber), true 132 } 133 return 0, false 134 } 135 136 /* utilities }}} */ 137 138 type CompileError struct { // {{{ 139 context *funcContext 140 Line int 141 Message string 142 } 143 144 func (e *CompileError) Error() string { 145 return fmt.Sprintf("compile error near line(%v) %v: %v", e.Line, e.context.Proto.SourceName, e.Message) 146 } // }}} 147 148 type codeStore struct { // {{{ 149 codes []uint32 150 lines []int 151 pc int 152 } 153 154 func (cd *codeStore) Add(inst uint32, line int) { 155 if l := len(cd.codes); l <= 0 || cd.pc == l { 156 cd.codes = append(cd.codes, inst) 157 cd.lines = append(cd.lines, line) 158 } else { 159 cd.codes[cd.pc] = inst 160 cd.lines[cd.pc] = line 161 } 162 cd.pc++ 163 } 164 165 func (cd *codeStore) AddABC(op int, a int, b int, c int, line int) { 166 cd.Add(opCreateABC(op, a, b, c), line) 167 } 168 169 func (cd *codeStore) AddABx(op int, a int, bx int, line int) { 170 cd.Add(opCreateABx(op, a, bx), line) 171 } 172 173 func (cd *codeStore) AddASbx(op int, a int, sbx int, line int) { 174 cd.Add(opCreateASbx(op, a, sbx), line) 175 } 176 177 func (cd *codeStore) PropagateKMV(top int, save *int, reg *int, inc int) { 178 lastinst := cd.Last() 179 if opGetArgA(lastinst) >= top { 180 switch opGetOpCode(lastinst) { 181 case OP_LOADK: 182 cindex := opGetArgBx(lastinst) 183 if cindex <= opMaxIndexRk { 184 cd.Pop() 185 *save = opRkAsk(cindex) 186 return 187 } 188 case OP_MOVE: 189 cd.Pop() 190 *save = opGetArgB(lastinst) 191 return 192 } 193 } 194 *save = *reg 195 *reg = *reg + inc 196 } 197 198 func (cd *codeStore) PropagateMV(top int, save *int, reg *int, inc int) { 199 lastinst := cd.Last() 200 if opGetArgA(lastinst) >= top { 201 switch opGetOpCode(lastinst) { 202 case OP_MOVE: 203 cd.Pop() 204 *save = opGetArgB(lastinst) 205 return 206 } 207 } 208 *save = *reg 209 *reg = *reg + inc 210 } 211 212 func (cd *codeStore) AddLoadNil(a, b, line int) { 213 last := cd.Last() 214 if opGetOpCode(last) == OP_LOADNIL && (opGetArgA(last)+opGetArgB(last)) == a { 215 cd.SetB(cd.LastPC(), b) 216 } else { 217 cd.AddABC(OP_LOADNIL, a, b, 0, line) 218 } 219 } 220 221 func (cd *codeStore) SetOpCode(pc int, v int) { 222 opSetOpCode(&cd.codes[pc], v) 223 } 224 225 func (cd *codeStore) SetA(pc int, v int) { 226 opSetArgA(&cd.codes[pc], v) 227 } 228 229 func (cd *codeStore) SetB(pc int, v int) { 230 opSetArgB(&cd.codes[pc], v) 231 } 232 233 func (cd *codeStore) SetC(pc int, v int) { 234 opSetArgC(&cd.codes[pc], v) 235 } 236 237 func (cd *codeStore) SetBx(pc int, v int) { 238 opSetArgBx(&cd.codes[pc], v) 239 } 240 241 func (cd *codeStore) SetSbx(pc int, v int) { 242 opSetArgSbx(&cd.codes[pc], v) 243 } 244 245 func (cd *codeStore) At(pc int) uint32 { 246 return cd.codes[pc] 247 } 248 249 func (cd *codeStore) List() []uint32 { 250 return cd.codes[:cd.pc] 251 } 252 253 func (cd *codeStore) PosList() []int { 254 return cd.lines[:cd.pc] 255 } 256 257 func (cd *codeStore) LastPC() int { 258 return cd.pc - 1 259 } 260 261 func (cd *codeStore) Last() uint32 { 262 if cd.pc == 0 { 263 return opInvalidInstruction 264 } 265 return cd.codes[cd.pc-1] 266 } 267 268 func (cd *codeStore) Pop() { 269 cd.pc-- 270 } /* }}} Code */ 271 272 /* {{{ VarNamePool */ 273 274 type varNamePoolValue struct { 275 Index int 276 Name string 277 } 278 279 type varNamePool struct { 280 names []string 281 offset int 282 } 283 284 func newVarNamePool(offset int) *varNamePool { 285 return &varNamePool{make([]string, 0, 16), offset} 286 } 287 288 func (vp *varNamePool) Names() []string { 289 return vp.names 290 } 291 292 func (vp *varNamePool) List() []varNamePoolValue { 293 result := make([]varNamePoolValue, len(vp.names), len(vp.names)) 294 for i, name := range vp.names { 295 result[i].Index = i + vp.offset 296 result[i].Name = name 297 } 298 return result 299 } 300 301 func (vp *varNamePool) LastIndex() int { 302 return vp.offset + len(vp.names) 303 } 304 305 func (vp *varNamePool) Find(name string) int { 306 for i := len(vp.names) - 1; i >= 0; i-- { 307 if vp.names[i] == name { 308 return i + vp.offset 309 } 310 } 311 return -1 312 } 313 314 func (vp *varNamePool) RegisterUnique(name string) int { 315 index := vp.Find(name) 316 if index < 0 { 317 return vp.Register(name) 318 } 319 return index 320 } 321 322 func (vp *varNamePool) Register(name string) int { 323 vp.names = append(vp.names, name) 324 return len(vp.names) - 1 + vp.offset 325 } 326 327 /* }}} VarNamePool */ 328 329 /* FuncContext {{{ */ 330 331 type codeBlock struct { 332 LocalVars *varNamePool 333 BreakLabel int 334 Parent *codeBlock 335 RefUpvalue bool 336 LineStart int 337 LastLine int 338 } 339 340 func newCodeBlock(localvars *varNamePool, blabel int, parent *codeBlock, pos ast.PositionHolder) *codeBlock { 341 bl := &codeBlock{localvars, blabel, parent, false, 0, 0} 342 if pos != nil { 343 bl.LineStart = pos.Line() 344 bl.LastLine = pos.LastLine() 345 } 346 return bl 347 } 348 349 type funcContext struct { 350 Proto *FunctionProto 351 Code *codeStore 352 Parent *funcContext 353 Upvalues *varNamePool 354 Block *codeBlock 355 Blocks []*codeBlock 356 regTop int 357 labelId int 358 labelPc map[int]int 359 } 360 361 func newFuncContext(sourcename string, parent *funcContext) *funcContext { 362 fc := &funcContext{ 363 Proto: newFunctionProto(sourcename), 364 Code: &codeStore{make([]uint32, 0, 1024), make([]int, 0, 1024), 0}, 365 Parent: parent, 366 Upvalues: newVarNamePool(0), 367 Block: newCodeBlock(newVarNamePool(0), labelNoJump, nil, nil), 368 regTop: 0, 369 labelId: 1, 370 labelPc: map[int]int{}, 371 } 372 fc.Blocks = []*codeBlock{fc.Block} 373 return fc 374 } 375 376 func (fc *funcContext) NewLabel() int { 377 ret := fc.labelId 378 fc.labelId++ 379 return ret 380 } 381 382 func (fc *funcContext) SetLabelPc(label int, pc int) { 383 fc.labelPc[label] = pc 384 } 385 386 func (fc *funcContext) GetLabelPc(label int) int { 387 return fc.labelPc[label] 388 } 389 390 func (fc *funcContext) ConstIndex(value LValue) int { 391 ctype := value.Type() 392 for i, lv := range fc.Proto.Constants { 393 if lv.Type() == ctype && lv == value { 394 return i 395 } 396 } 397 fc.Proto.Constants = append(fc.Proto.Constants, value) 398 v := len(fc.Proto.Constants) - 1 399 if v > opMaxArgBx { 400 raiseCompileError(fc, fc.Proto.LineDefined, "too many constants") 401 } 402 return v 403 } 404 405 func (fc *funcContext) RegisterLocalVar(name string) int { 406 ret := fc.Block.LocalVars.Register(name) 407 fc.Proto.DbgLocals = append(fc.Proto.DbgLocals, &DbgLocalInfo{Name: name, StartPc: fc.Code.LastPC() + 1}) 408 fc.SetRegTop(fc.RegTop() + 1) 409 return ret 410 } 411 412 func (fc *funcContext) FindLocalVarAndBlock(name string) (int, *codeBlock) { 413 for block := fc.Block; block != nil; block = block.Parent { 414 if index := block.LocalVars.Find(name); index > -1 { 415 return index, block 416 } 417 } 418 return -1, nil 419 } 420 421 func (fc *funcContext) FindLocalVar(name string) int { 422 idx, _ := fc.FindLocalVarAndBlock(name) 423 return idx 424 } 425 426 func (fc *funcContext) LocalVars() []varNamePoolValue { 427 result := make([]varNamePoolValue, 0, 32) 428 for _, block := range fc.Blocks { 429 result = append(result, block.LocalVars.List()...) 430 } 431 return result 432 } 433 434 func (fc *funcContext) EnterBlock(blabel int, pos ast.PositionHolder) { 435 fc.Block = newCodeBlock(newVarNamePool(fc.RegTop()), blabel, fc.Block, pos) 436 fc.Blocks = append(fc.Blocks, fc.Block) 437 } 438 439 func (fc *funcContext) CloseUpvalues() int { 440 n := -1 441 if fc.Block.RefUpvalue { 442 n = fc.Block.Parent.LocalVars.LastIndex() 443 fc.Code.AddABC(OP_CLOSE, n, 0, 0, fc.Block.LastLine) 444 } 445 return n 446 } 447 448 func (fc *funcContext) LeaveBlock() int { 449 closed := fc.CloseUpvalues() 450 fc.EndScope() 451 fc.Block = fc.Block.Parent 452 fc.SetRegTop(fc.Block.LocalVars.LastIndex()) 453 return closed 454 } 455 456 func (fc *funcContext) EndScope() { 457 for _, vr := range fc.Block.LocalVars.List() { 458 fc.Proto.DbgLocals[vr.Index].EndPc = fc.Code.LastPC() 459 } 460 } 461 462 func (fc *funcContext) SetRegTop(top int) { 463 if top > maxRegisters { 464 raiseCompileError(fc, fc.Proto.LineDefined, "too many local variables") 465 } 466 fc.regTop = top 467 } 468 469 func (fc *funcContext) RegTop() int { 470 return fc.regTop 471 } 472 473 /* FuncContext }}} */ 474 475 func compileChunk(context *funcContext, chunk []ast.Stmt) { // {{{ 476 for _, stmt := range chunk { 477 compileStmt(context, stmt) 478 } 479 } // }}} 480 481 func compileBlock(context *funcContext, chunk []ast.Stmt) { // {{{ 482 if len(chunk) == 0 { 483 return 484 } 485 ph := &ast.Node{} 486 ph.SetLine(sline(chunk[0])) 487 ph.SetLastLine(eline(chunk[len(chunk)-1])) 488 context.EnterBlock(labelNoJump, ph) 489 for _, stmt := range chunk { 490 compileStmt(context, stmt) 491 } 492 context.LeaveBlock() 493 } // }}} 494 495 func compileStmt(context *funcContext, stmt ast.Stmt) { // {{{ 496 switch st := stmt.(type) { 497 case *ast.AssignStmt: 498 compileAssignStmt(context, st) 499 case *ast.LocalAssignStmt: 500 compileLocalAssignStmt(context, st) 501 case *ast.FuncCallStmt: 502 compileFuncCallExpr(context, context.RegTop(), st.Expr.(*ast.FuncCallExpr), ecnone(-1)) 503 case *ast.DoBlockStmt: 504 context.EnterBlock(labelNoJump, st) 505 compileChunk(context, st.Stmts) 506 context.LeaveBlock() 507 case *ast.WhileStmt: 508 compileWhileStmt(context, st) 509 case *ast.RepeatStmt: 510 compileRepeatStmt(context, st) 511 case *ast.FuncDefStmt: 512 compileFuncDefStmt(context, st) 513 case *ast.ReturnStmt: 514 compileReturnStmt(context, st) 515 case *ast.IfStmt: 516 compileIfStmt(context, st) 517 case *ast.BreakStmt: 518 compileBreakStmt(context, st) 519 case *ast.NumberForStmt: 520 compileNumberForStmt(context, st) 521 case *ast.GenericForStmt: 522 compileGenericForStmt(context, st) 523 } 524 } // }}} 525 526 func compileAssignStmtLeft(context *funcContext, stmt *ast.AssignStmt) (int, []*assigncontext) { // {{{ 527 reg := context.RegTop() 528 acs := make([]*assigncontext, 0, len(stmt.Lhs)) 529 for i, lhs := range stmt.Lhs { 530 islast := i == len(stmt.Lhs)-1 531 switch st := lhs.(type) { 532 case *ast.IdentExpr: 533 identtype := getIdentRefType(context, context, st) 534 ec := &expcontext{identtype, regNotDefined, 0} 535 switch identtype { 536 case ecGlobal: 537 context.ConstIndex(LString(st.Value)) 538 case ecUpvalue: 539 context.Upvalues.RegisterUnique(st.Value) 540 case ecLocal: 541 if islast { 542 ec.reg = context.FindLocalVar(st.Value) 543 } 544 } 545 acs = append(acs, &assigncontext{ec, 0, 0, false, false}) 546 case *ast.AttrGetExpr: 547 ac := &assigncontext{&expcontext{ecTable, regNotDefined, 0}, 0, 0, false, false} 548 compileExprWithKMVPropagation(context, st.Object, ®, &ac.ec.reg) 549 ac.keyrk = reg 550 reg += compileExpr(context, reg, st.Key, ecnone(0)) 551 if _, ok := st.Key.(*ast.StringExpr); ok { 552 ac.keyks = true 553 } 554 acs = append(acs, ac) 555 556 default: 557 panic("invalid left expression.") 558 } 559 } 560 return reg, acs 561 } // }}} 562 563 func compileAssignStmtRight(context *funcContext, stmt *ast.AssignStmt, reg int, acs []*assigncontext) (int, []*assigncontext) { // {{{ 564 lennames := len(stmt.Lhs) 565 lenexprs := len(stmt.Rhs) 566 namesassigned := 0 567 568 for namesassigned < lennames { 569 ac := acs[namesassigned] 570 ec := ac.ec 571 var expr ast.Expr = nil 572 if namesassigned >= lenexprs { 573 expr = &ast.NilExpr{} 574 expr.SetLine(sline(stmt.Lhs[namesassigned])) 575 expr.SetLastLine(eline(stmt.Lhs[namesassigned])) 576 } else if isVarArgReturnExpr(stmt.Rhs[namesassigned]) && (lenexprs-namesassigned-1) <= 0 { 577 varargopt := lennames - namesassigned - 1 578 regstart := reg 579 reginc := compileExpr(context, reg, stmt.Rhs[namesassigned], ecnone(varargopt)) 580 reg += reginc 581 for i := namesassigned; i < namesassigned+int(reginc); i++ { 582 acs[i].needmove = true 583 if acs[i].ec.ctype == ecTable { 584 acs[i].valuerk = regstart + (i - namesassigned) 585 } 586 } 587 namesassigned = lennames 588 continue 589 } 590 591 if expr == nil { 592 expr = stmt.Rhs[namesassigned] 593 } 594 idx := reg 595 reginc := compileExpr(context, reg, expr, ec) 596 if ec.ctype == ecTable { 597 if _, ok := expr.(*ast.LogicalOpExpr); !ok { 598 context.Code.PropagateKMV(context.RegTop(), &ac.valuerk, ®, reginc) 599 } else { 600 ac.valuerk = idx 601 reg += reginc 602 } 603 } else { 604 ac.needmove = reginc != 0 605 reg += reginc 606 } 607 namesassigned += 1 608 } 609 610 rightreg := reg - 1 611 612 // extra right exprs 613 for i := namesassigned; i < lenexprs; i++ { 614 varargopt := -1 615 if i != lenexprs-1 { 616 varargopt = 0 617 } 618 reg += compileExpr(context, reg, stmt.Rhs[i], ecnone(varargopt)) 619 } 620 return rightreg, acs 621 } // }}} 622 623 func compileAssignStmt(context *funcContext, stmt *ast.AssignStmt) { // {{{ 624 code := context.Code 625 lennames := len(stmt.Lhs) 626 reg, acs := compileAssignStmtLeft(context, stmt) 627 reg, acs = compileAssignStmtRight(context, stmt, reg, acs) 628 629 for i := lennames - 1; i >= 0; i-- { 630 ex := stmt.Lhs[i] 631 switch acs[i].ec.ctype { 632 case ecLocal: 633 if acs[i].needmove { 634 code.AddABC(OP_MOVE, context.FindLocalVar(ex.(*ast.IdentExpr).Value), reg, 0, sline(ex)) 635 reg -= 1 636 } 637 case ecGlobal: 638 code.AddABx(OP_SETGLOBAL, reg, context.ConstIndex(LString(ex.(*ast.IdentExpr).Value)), sline(ex)) 639 reg -= 1 640 case ecUpvalue: 641 code.AddABC(OP_SETUPVAL, reg, context.Upvalues.RegisterUnique(ex.(*ast.IdentExpr).Value), 0, sline(ex)) 642 reg -= 1 643 case ecTable: 644 opcode := OP_SETTABLE 645 if acs[i].keyks { 646 opcode = OP_SETTABLEKS 647 } 648 code.AddABC(opcode, acs[i].ec.reg, acs[i].keyrk, acs[i].valuerk, sline(ex)) 649 if !opIsK(acs[i].valuerk) { 650 reg -= 1 651 } 652 } 653 } 654 } // }}} 655 656 func compileRegAssignment(context *funcContext, names []string, exprs []ast.Expr, reg int, nvars int, line int) { // {{{ 657 lennames := len(names) 658 lenexprs := len(exprs) 659 namesassigned := 0 660 ec := &expcontext{} 661 662 for namesassigned < lennames && namesassigned < lenexprs { 663 if isVarArgReturnExpr(exprs[namesassigned]) && (lenexprs-namesassigned-1) <= 0 { 664 665 varargopt := nvars - namesassigned 666 ecupdate(ec, ecVararg, reg, varargopt-1) 667 compileExpr(context, reg, exprs[namesassigned], ec) 668 reg += varargopt 669 namesassigned = lennames 670 } else { 671 ecupdate(ec, ecLocal, reg, 0) 672 compileExpr(context, reg, exprs[namesassigned], ec) 673 reg += 1 674 namesassigned += 1 675 } 676 } 677 678 // extra left names 679 if lennames > namesassigned { 680 restleft := lennames - namesassigned - 1 681 context.Code.AddLoadNil(reg, reg+restleft, line) 682 reg += restleft 683 } 684 685 // extra right exprs 686 for i := namesassigned; i < lenexprs; i++ { 687 varargopt := -1 688 if i != lenexprs-1 { 689 varargopt = 0 690 } 691 ecupdate(ec, ecNone, reg, varargopt) 692 reg += compileExpr(context, reg, exprs[i], ec) 693 } 694 } // }}} 695 696 func compileLocalAssignStmt(context *funcContext, stmt *ast.LocalAssignStmt) { // {{{ 697 reg := context.RegTop() 698 if len(stmt.Names) == 1 && len(stmt.Exprs) == 1 { 699 if _, ok := stmt.Exprs[0].(*ast.FunctionExpr); ok { 700 context.RegisterLocalVar(stmt.Names[0]) 701 compileRegAssignment(context, stmt.Names, stmt.Exprs, reg, len(stmt.Names), sline(stmt)) 702 return 703 } 704 } 705 706 compileRegAssignment(context, stmt.Names, stmt.Exprs, reg, len(stmt.Names), sline(stmt)) 707 for _, name := range stmt.Names { 708 context.RegisterLocalVar(name) 709 } 710 } // }}} 711 712 func compileReturnStmt(context *funcContext, stmt *ast.ReturnStmt) { // {{{ 713 lenexprs := len(stmt.Exprs) 714 code := context.Code 715 reg := context.RegTop() 716 a := reg 717 lastisvaarg := false 718 719 if lenexprs == 1 { 720 switch ex := stmt.Exprs[0].(type) { 721 case *ast.IdentExpr: 722 if idx := context.FindLocalVar(ex.Value); idx > -1 { 723 code.AddABC(OP_RETURN, idx, 2, 0, sline(stmt)) 724 return 725 } 726 case *ast.FuncCallExpr: 727 reg += compileExpr(context, reg, ex, ecnone(-2)) 728 code.SetOpCode(code.LastPC(), OP_TAILCALL) 729 code.AddABC(OP_RETURN, a, 0, 0, sline(stmt)) 730 return 731 } 732 } 733 734 for i, expr := range stmt.Exprs { 735 if i == lenexprs-1 && isVarArgReturnExpr(expr) { 736 compileExpr(context, reg, expr, ecnone(-2)) 737 lastisvaarg = true 738 } else { 739 reg += compileExpr(context, reg, expr, ecnone(0)) 740 } 741 } 742 count := reg - a + 1 743 if lastisvaarg { 744 count = 0 745 } 746 context.Code.AddABC(OP_RETURN, a, count, 0, sline(stmt)) 747 } // }}} 748 749 func compileIfStmt(context *funcContext, stmt *ast.IfStmt) { // {{{ 750 thenlabel := context.NewLabel() 751 elselabel := context.NewLabel() 752 endlabel := context.NewLabel() 753 754 compileBranchCondition(context, context.RegTop(), stmt.Condition, thenlabel, elselabel, false) 755 context.SetLabelPc(thenlabel, context.Code.LastPC()) 756 compileBlock(context, stmt.Then) 757 if len(stmt.Else) > 0 { 758 context.Code.AddASbx(OP_JMP, 0, endlabel, sline(stmt)) 759 } 760 context.SetLabelPc(elselabel, context.Code.LastPC()) 761 if len(stmt.Else) > 0 { 762 compileBlock(context, stmt.Else) 763 context.SetLabelPc(endlabel, context.Code.LastPC()) 764 } 765 766 } // }}} 767 768 func compileBranchCondition(context *funcContext, reg int, expr ast.Expr, thenlabel, elselabel int, hasnextcond bool) { // {{{ 769 // TODO folding constants? 770 code := context.Code 771 flip := 0 772 jumplabel := elselabel 773 if hasnextcond { 774 flip = 1 775 jumplabel = thenlabel 776 } 777 778 switch ex := expr.(type) { 779 case *ast.FalseExpr, *ast.NilExpr: 780 if !hasnextcond { 781 code.AddASbx(OP_JMP, 0, elselabel, sline(expr)) 782 return 783 } 784 case *ast.TrueExpr, *ast.NumberExpr, *ast.StringExpr: 785 if !hasnextcond { 786 return 787 } 788 case *ast.UnaryNotOpExpr: 789 compileBranchCondition(context, reg, ex.Expr, elselabel, thenlabel, !hasnextcond) 790 return 791 case *ast.LogicalOpExpr: 792 switch ex.Operator { 793 case "and": 794 nextcondlabel := context.NewLabel() 795 compileBranchCondition(context, reg, ex.Lhs, nextcondlabel, elselabel, false) 796 context.SetLabelPc(nextcondlabel, context.Code.LastPC()) 797 compileBranchCondition(context, reg, ex.Rhs, thenlabel, elselabel, hasnextcond) 798 case "or": 799 nextcondlabel := context.NewLabel() 800 compileBranchCondition(context, reg, ex.Lhs, thenlabel, nextcondlabel, true) 801 context.SetLabelPc(nextcondlabel, context.Code.LastPC()) 802 compileBranchCondition(context, reg, ex.Rhs, thenlabel, elselabel, hasnextcond) 803 } 804 return 805 case *ast.RelationalOpExpr: 806 compileRelationalOpExprAux(context, reg, ex, flip, jumplabel) 807 return 808 } 809 810 a := reg 811 compileExprWithMVPropagation(context, expr, ®, &a) 812 code.AddABC(OP_TEST, a, 0, 0^flip, sline(expr)) 813 code.AddASbx(OP_JMP, 0, jumplabel, sline(expr)) 814 } // }}} 815 816 func compileWhileStmt(context *funcContext, stmt *ast.WhileStmt) { // {{{ 817 thenlabel := context.NewLabel() 818 elselabel := context.NewLabel() 819 condlabel := context.NewLabel() 820 821 context.SetLabelPc(condlabel, context.Code.LastPC()) 822 compileBranchCondition(context, context.RegTop(), stmt.Condition, thenlabel, elselabel, false) 823 context.SetLabelPc(thenlabel, context.Code.LastPC()) 824 context.EnterBlock(elselabel, stmt) 825 compileChunk(context, stmt.Stmts) 826 context.CloseUpvalues() 827 context.Code.AddASbx(OP_JMP, 0, condlabel, eline(stmt)) 828 context.LeaveBlock() 829 context.SetLabelPc(elselabel, context.Code.LastPC()) 830 } // }}} 831 832 func compileRepeatStmt(context *funcContext, stmt *ast.RepeatStmt) { // {{{ 833 initlabel := context.NewLabel() 834 thenlabel := context.NewLabel() 835 elselabel := context.NewLabel() 836 837 context.SetLabelPc(initlabel, context.Code.LastPC()) 838 context.SetLabelPc(elselabel, context.Code.LastPC()) 839 context.EnterBlock(thenlabel, stmt) 840 compileChunk(context, stmt.Stmts) 841 compileBranchCondition(context, context.RegTop(), stmt.Condition, thenlabel, elselabel, false) 842 843 context.SetLabelPc(thenlabel, context.Code.LastPC()) 844 n := context.LeaveBlock() 845 846 if n > -1 { 847 label := context.NewLabel() 848 context.Code.AddASbx(OP_JMP, 0, label, eline(stmt)) 849 context.SetLabelPc(elselabel, context.Code.LastPC()) 850 context.Code.AddABC(OP_CLOSE, n, 0, 0, eline(stmt)) 851 context.Code.AddASbx(OP_JMP, 0, initlabel, eline(stmt)) 852 context.SetLabelPc(label, context.Code.LastPC()) 853 } 854 855 } // }}} 856 857 func compileBreakStmt(context *funcContext, stmt *ast.BreakStmt) { // {{{ 858 for block := context.Block; block != nil; block = block.Parent { 859 if label := block.BreakLabel; label != labelNoJump { 860 if block.RefUpvalue { 861 context.Code.AddABC(OP_CLOSE, block.Parent.LocalVars.LastIndex(), 0, 0, sline(stmt)) 862 } 863 context.Code.AddASbx(OP_JMP, 0, label, sline(stmt)) 864 return 865 } 866 } 867 raiseCompileError(context, sline(stmt), "no loop to break") 868 } // }}} 869 870 func compileFuncDefStmt(context *funcContext, stmt *ast.FuncDefStmt) { // {{{ 871 if stmt.Name.Func == nil { 872 reg := context.RegTop() 873 var treg, kreg int 874 compileExprWithKMVPropagation(context, stmt.Name.Receiver, ®, &treg) 875 kreg = loadRk(context, ®, stmt.Func, LString(stmt.Name.Method)) 876 compileExpr(context, reg, stmt.Func, ecfuncdef) 877 context.Code.AddABC(OP_SETTABLE, treg, kreg, reg, sline(stmt.Name.Receiver)) 878 } else { 879 astmt := &ast.AssignStmt{Lhs: []ast.Expr{stmt.Name.Func}, Rhs: []ast.Expr{stmt.Func}} 880 astmt.SetLine(sline(stmt.Func)) 881 astmt.SetLastLine(eline(stmt.Func)) 882 compileAssignStmt(context, astmt) 883 } 884 } // }}} 885 886 func compileNumberForStmt(context *funcContext, stmt *ast.NumberForStmt) { // {{{ 887 code := context.Code 888 endlabel := context.NewLabel() 889 ec := &expcontext{} 890 891 context.EnterBlock(endlabel, stmt) 892 reg := context.RegTop() 893 rindex := context.RegisterLocalVar("(for index)") 894 ecupdate(ec, ecLocal, rindex, 0) 895 compileExpr(context, reg, stmt.Init, ec) 896 897 reg = context.RegTop() 898 rlimit := context.RegisterLocalVar("(for limit)") 899 ecupdate(ec, ecLocal, rlimit, 0) 900 compileExpr(context, reg, stmt.Limit, ec) 901 902 reg = context.RegTop() 903 rstep := context.RegisterLocalVar("(for step)") 904 if stmt.Step == nil { 905 stmt.Step = &ast.NumberExpr{Value: "1"} 906 stmt.Step.SetLine(sline(stmt.Init)) 907 } 908 ecupdate(ec, ecLocal, rstep, 0) 909 compileExpr(context, reg, stmt.Step, ec) 910 911 code.AddASbx(OP_FORPREP, rindex, 0, sline(stmt)) 912 913 context.RegisterLocalVar(stmt.Name) 914 915 bodypc := code.LastPC() 916 compileChunk(context, stmt.Stmts) 917 918 context.LeaveBlock() 919 920 flpc := code.LastPC() 921 code.AddASbx(OP_FORLOOP, rindex, bodypc-(flpc+1), sline(stmt)) 922 923 context.SetLabelPc(endlabel, code.LastPC()) 924 code.SetSbx(bodypc, flpc-bodypc) 925 926 } // }}} 927 928 func compileGenericForStmt(context *funcContext, stmt *ast.GenericForStmt) { // {{{ 929 code := context.Code 930 endlabel := context.NewLabel() 931 bodylabel := context.NewLabel() 932 fllabel := context.NewLabel() 933 nnames := len(stmt.Names) 934 935 context.EnterBlock(endlabel, stmt) 936 rgen := context.RegisterLocalVar("(for generator)") 937 context.RegisterLocalVar("(for state)") 938 context.RegisterLocalVar("(for control)") 939 940 compileRegAssignment(context, stmt.Names, stmt.Exprs, context.RegTop()-3, 3, sline(stmt)) 941 942 code.AddASbx(OP_JMP, 0, fllabel, sline(stmt)) 943 944 for _, name := range stmt.Names { 945 context.RegisterLocalVar(name) 946 } 947 948 context.SetLabelPc(bodylabel, code.LastPC()) 949 compileChunk(context, stmt.Stmts) 950 951 context.LeaveBlock() 952 953 context.SetLabelPc(fllabel, code.LastPC()) 954 code.AddABC(OP_TFORLOOP, rgen, 0, nnames, sline(stmt)) 955 code.AddASbx(OP_JMP, 0, bodylabel, sline(stmt)) 956 957 context.SetLabelPc(endlabel, code.LastPC()) 958 } // }}} 959 960 func compileExpr(context *funcContext, reg int, expr ast.Expr, ec *expcontext) int { // {{{ 961 code := context.Code 962 sreg := savereg(ec, reg) 963 sused := 1 964 if sreg < reg { 965 sused = 0 966 } 967 968 switch ex := expr.(type) { 969 case *ast.StringExpr: 970 code.AddABx(OP_LOADK, sreg, context.ConstIndex(LString(ex.Value)), sline(ex)) 971 return sused 972 case *ast.NumberExpr: 973 num, err := parseNumber(ex.Value) 974 if err != nil { 975 num = LNumber(math.NaN()) 976 } 977 code.AddABx(OP_LOADK, sreg, context.ConstIndex(num), sline(ex)) 978 return sused 979 case *constLValueExpr: 980 code.AddABx(OP_LOADK, sreg, context.ConstIndex(ex.Value), sline(ex)) 981 return sused 982 case *ast.NilExpr: 983 code.AddLoadNil(sreg, sreg, sline(ex)) 984 return sused 985 case *ast.FalseExpr: 986 code.AddABC(OP_LOADBOOL, sreg, 0, 0, sline(ex)) 987 return sused 988 case *ast.TrueExpr: 989 code.AddABC(OP_LOADBOOL, sreg, 1, 0, sline(ex)) 990 return sused 991 case *ast.IdentExpr: 992 switch getIdentRefType(context, context, ex) { 993 case ecGlobal: 994 code.AddABx(OP_GETGLOBAL, sreg, context.ConstIndex(LString(ex.Value)), sline(ex)) 995 case ecUpvalue: 996 code.AddABC(OP_GETUPVAL, sreg, context.Upvalues.RegisterUnique(ex.Value), 0, sline(ex)) 997 case ecLocal: 998 b := context.FindLocalVar(ex.Value) 999 code.AddABC(OP_MOVE, sreg, b, 0, sline(ex)) 1000 } 1001 return sused 1002 case *ast.Comma3Expr: 1003 if context.Proto.IsVarArg == 0 { 1004 raiseCompileError(context, sline(ex), "cannot use '...' outside a vararg function") 1005 } 1006 context.Proto.IsVarArg &= ^VarArgNeedsArg 1007 code.AddABC(OP_VARARG, sreg, 2+ec.varargopt, 0, sline(ex)) 1008 if context.RegTop() > (sreg+2+ec.varargopt) || ec.varargopt < -1 { 1009 return 0 1010 } 1011 return (sreg + 1 + ec.varargopt) - reg 1012 case *ast.AttrGetExpr: 1013 a := sreg 1014 b := reg 1015 compileExprWithMVPropagation(context, ex.Object, ®, &b) 1016 c := reg 1017 compileExprWithKMVPropagation(context, ex.Key, ®, &c) 1018 opcode := OP_GETTABLE 1019 if _, ok := ex.Key.(*ast.StringExpr); ok { 1020 opcode = OP_GETTABLEKS 1021 } 1022 code.AddABC(opcode, a, b, c, sline(ex)) 1023 return sused 1024 case *ast.TableExpr: 1025 compileTableExpr(context, reg, ex, ec) 1026 return 1 1027 case *ast.ArithmeticOpExpr: 1028 compileArithmeticOpExpr(context, reg, ex, ec) 1029 return sused 1030 case *ast.StringConcatOpExpr: 1031 compileStringConcatOpExpr(context, reg, ex, ec) 1032 return sused 1033 case *ast.UnaryMinusOpExpr, *ast.UnaryNotOpExpr, *ast.UnaryLenOpExpr: 1034 compileUnaryOpExpr(context, reg, ex, ec) 1035 return sused 1036 case *ast.RelationalOpExpr: 1037 compileRelationalOpExpr(context, reg, ex, ec) 1038 return sused 1039 case *ast.LogicalOpExpr: 1040 compileLogicalOpExpr(context, reg, ex, ec) 1041 return sused 1042 case *ast.FuncCallExpr: 1043 return compileFuncCallExpr(context, reg, ex, ec) 1044 case *ast.FunctionExpr: 1045 childcontext := newFuncContext(context.Proto.SourceName, context) 1046 compileFunctionExpr(childcontext, ex, ec) 1047 protono := len(context.Proto.FunctionPrototypes) 1048 context.Proto.FunctionPrototypes = append(context.Proto.FunctionPrototypes, childcontext.Proto) 1049 code.AddABx(OP_CLOSURE, sreg, protono, sline(ex)) 1050 for _, upvalue := range childcontext.Upvalues.List() { 1051 localidx, block := context.FindLocalVarAndBlock(upvalue.Name) 1052 if localidx > -1 { 1053 code.AddABC(OP_MOVE, 0, localidx, 0, sline(ex)) 1054 block.RefUpvalue = true 1055 } else { 1056 upvalueidx := context.Upvalues.Find(upvalue.Name) 1057 if upvalueidx < 0 { 1058 upvalueidx = context.Upvalues.RegisterUnique(upvalue.Name) 1059 } 1060 code.AddABC(OP_GETUPVAL, 0, upvalueidx, 0, sline(ex)) 1061 } 1062 } 1063 return sused 1064 default: 1065 panic(fmt.Sprintf("expr %v not implemented.", reflect.TypeOf(ex).Elem().Name())) 1066 } 1067 1068 } // }}} 1069 1070 func compileExprWithPropagation(context *funcContext, expr ast.Expr, reg *int, save *int, propergator func(int, *int, *int, int)) { // {{{ 1071 reginc := compileExpr(context, *reg, expr, ecnone(0)) 1072 if _, ok := expr.(*ast.LogicalOpExpr); ok { 1073 *save = *reg 1074 *reg = *reg + reginc 1075 } else { 1076 propergator(context.RegTop(), save, reg, reginc) 1077 } 1078 } // }}} 1079 1080 func compileExprWithKMVPropagation(context *funcContext, expr ast.Expr, reg *int, save *int) { // {{{ 1081 compileExprWithPropagation(context, expr, reg, save, context.Code.PropagateKMV) 1082 } // }}} 1083 1084 func compileExprWithMVPropagation(context *funcContext, expr ast.Expr, reg *int, save *int) { // {{{ 1085 compileExprWithPropagation(context, expr, reg, save, context.Code.PropagateMV) 1086 } // }}} 1087 1088 func constFold(exp ast.Expr) ast.Expr { // {{{ 1089 switch expr := exp.(type) { 1090 case *ast.ArithmeticOpExpr: 1091 lvalue, lisconst := lnumberValue(constFold(expr.Lhs)) 1092 rvalue, risconst := lnumberValue(constFold(expr.Rhs)) 1093 if lisconst && risconst { 1094 switch expr.Operator { 1095 case "+": 1096 return &constLValueExpr{Value: lvalue + rvalue} 1097 case "-": 1098 return &constLValueExpr{Value: lvalue - rvalue} 1099 case "*": 1100 return &constLValueExpr{Value: lvalue * rvalue} 1101 case "/": 1102 return &constLValueExpr{Value: lvalue / rvalue} 1103 case "%": 1104 return &constLValueExpr{Value: luaModulo(lvalue, rvalue)} 1105 case "^": 1106 return &constLValueExpr{Value: LNumber(math.Pow(float64(lvalue), float64(rvalue)))} 1107 default: 1108 panic(fmt.Sprintf("unknown binop: %v", expr.Operator)) 1109 } 1110 } else { 1111 return expr 1112 } 1113 case *ast.UnaryMinusOpExpr: 1114 expr.Expr = constFold(expr.Expr) 1115 if value, ok := lnumberValue(expr.Expr); ok { 1116 return &constLValueExpr{Value: LNumber(-value)} 1117 } 1118 return expr 1119 default: 1120 1121 return exp 1122 } 1123 } // }}} 1124 1125 func compileFunctionExpr(context *funcContext, funcexpr *ast.FunctionExpr, ec *expcontext) { // {{{ 1126 context.Proto.LineDefined = sline(funcexpr) 1127 context.Proto.LastLineDefined = eline(funcexpr) 1128 if len(funcexpr.ParList.Names) > maxRegisters { 1129 raiseCompileError(context, context.Proto.LineDefined, "register overflow") 1130 } 1131 context.Proto.NumParameters = uint8(len(funcexpr.ParList.Names)) 1132 if ec.ctype == ecMethod { 1133 context.Proto.NumParameters += 1 1134 context.RegisterLocalVar("self") 1135 } 1136 for _, name := range funcexpr.ParList.Names { 1137 context.RegisterLocalVar(name) 1138 } 1139 if funcexpr.ParList.HasVargs { 1140 if CompatVarArg { 1141 context.Proto.IsVarArg = VarArgHasArg | VarArgNeedsArg 1142 if context.Parent != nil { 1143 context.RegisterLocalVar("arg") 1144 } 1145 } 1146 context.Proto.IsVarArg |= VarArgIsVarArg 1147 } 1148 1149 compileChunk(context, funcexpr.Stmts) 1150 1151 context.Code.AddABC(OP_RETURN, 0, 1, 0, eline(funcexpr)) 1152 context.EndScope() 1153 context.Proto.Code = context.Code.List() 1154 context.Proto.DbgSourcePositions = context.Code.PosList() 1155 context.Proto.DbgUpvalues = context.Upvalues.Names() 1156 context.Proto.NumUpvalues = uint8(len(context.Proto.DbgUpvalues)) 1157 for _, clv := range context.Proto.Constants { 1158 sv := "" 1159 if slv, ok := clv.(LString); ok { 1160 sv = string(slv) 1161 } 1162 context.Proto.stringConstants = append(context.Proto.stringConstants, sv) 1163 } 1164 patchCode(context) 1165 } // }}} 1166 1167 func compileTableExpr(context *funcContext, reg int, ex *ast.TableExpr, ec *expcontext) { // {{{ 1168 code := context.Code 1169 /* 1170 tablereg := savereg(ec, reg) 1171 if tablereg == reg { 1172 reg += 1 1173 } 1174 */ 1175 tablereg := reg 1176 reg++ 1177 code.AddABC(OP_NEWTABLE, tablereg, 0, 0, sline(ex)) 1178 tablepc := code.LastPC() 1179 regbase := reg 1180 1181 arraycount := 0 1182 lastvararg := false 1183 for i, field := range ex.Fields { 1184 islast := i == len(ex.Fields)-1 1185 if field.Key == nil { 1186 if islast && isVarArgReturnExpr(field.Value) { 1187 reg += compileExpr(context, reg, field.Value, ecnone(-2)) 1188 lastvararg = true 1189 } else { 1190 reg += compileExpr(context, reg, field.Value, ecnone(0)) 1191 arraycount += 1 1192 } 1193 } else { 1194 regorg := reg 1195 b := reg 1196 compileExprWithKMVPropagation(context, field.Key, ®, &b) 1197 c := reg 1198 compileExprWithKMVPropagation(context, field.Value, ®, &c) 1199 opcode := OP_SETTABLE 1200 if _, ok := field.Key.(*ast.StringExpr); ok { 1201 opcode = OP_SETTABLEKS 1202 } 1203 code.AddABC(opcode, tablereg, b, c, sline(ex)) 1204 reg = regorg 1205 } 1206 flush := arraycount % FieldsPerFlush 1207 if (arraycount != 0 && (flush == 0 || islast)) || lastvararg { 1208 reg = regbase 1209 num := flush 1210 if num == 0 { 1211 num = FieldsPerFlush 1212 } 1213 c := (arraycount-1)/FieldsPerFlush + 1 1214 b := num 1215 if islast && isVarArgReturnExpr(field.Value) { 1216 b = 0 1217 } 1218 line := field.Value 1219 if field.Key != nil { 1220 line = field.Key 1221 } 1222 if c > 511 { 1223 c = 0 1224 } 1225 code.AddABC(OP_SETLIST, tablereg, b, c, sline(line)) 1226 if c == 0 { 1227 code.Add(uint32(c), sline(line)) 1228 } 1229 } 1230 } 1231 code.SetB(tablepc, int2Fb(arraycount)) 1232 code.SetC(tablepc, int2Fb(len(ex.Fields)-arraycount)) 1233 if shouldmove(ec, tablereg) { 1234 code.AddABC(OP_MOVE, ec.reg, tablereg, 0, sline(ex)) 1235 } 1236 } // }}} 1237 1238 func compileArithmeticOpExpr(context *funcContext, reg int, expr *ast.ArithmeticOpExpr, ec *expcontext) { // {{{ 1239 exp := constFold(expr) 1240 if ex, ok := exp.(*constLValueExpr); ok { 1241 exp.SetLine(sline(expr)) 1242 compileExpr(context, reg, ex, ec) 1243 return 1244 } 1245 expr, _ = exp.(*ast.ArithmeticOpExpr) 1246 a := savereg(ec, reg) 1247 b := reg 1248 compileExprWithKMVPropagation(context, expr.Lhs, ®, &b) 1249 c := reg 1250 compileExprWithKMVPropagation(context, expr.Rhs, ®, &c) 1251 1252 op := 0 1253 switch expr.Operator { 1254 case "+": 1255 op = OP_ADD 1256 case "-": 1257 op = OP_SUB 1258 case "*": 1259 op = OP_MUL 1260 case "/": 1261 op = OP_DIV 1262 case "%": 1263 op = OP_MOD 1264 case "^": 1265 op = OP_POW 1266 } 1267 context.Code.AddABC(op, a, b, c, sline(expr)) 1268 } // }}} 1269 1270 func compileStringConcatOpExpr(context *funcContext, reg int, expr *ast.StringConcatOpExpr, ec *expcontext) { // {{{ 1271 code := context.Code 1272 crange := 1 1273 for current := expr.Rhs; current != nil; { 1274 if ex, ok := current.(*ast.StringConcatOpExpr); ok { 1275 crange += 1 1276 current = ex.Rhs 1277 } else { 1278 current = nil 1279 } 1280 } 1281 a := savereg(ec, reg) 1282 basereg := reg 1283 reg += compileExpr(context, reg, expr.Lhs, ecnone(0)) 1284 reg += compileExpr(context, reg, expr.Rhs, ecnone(0)) 1285 for pc := code.LastPC(); pc != 0 && opGetOpCode(code.At(pc)) == OP_CONCAT; pc-- { 1286 code.Pop() 1287 } 1288 code.AddABC(OP_CONCAT, a, basereg, basereg+crange, sline(expr)) 1289 } // }}} 1290 1291 func compileUnaryOpExpr(context *funcContext, reg int, expr ast.Expr, ec *expcontext) { // {{{ 1292 opcode := 0 1293 code := context.Code 1294 var operandexpr ast.Expr 1295 switch ex := expr.(type) { 1296 case *ast.UnaryMinusOpExpr: 1297 exp := constFold(ex) 1298 if lvexpr, ok := exp.(*constLValueExpr); ok { 1299 exp.SetLine(sline(expr)) 1300 compileExpr(context, reg, lvexpr, ec) 1301 return 1302 } 1303 ex, _ = exp.(*ast.UnaryMinusOpExpr) 1304 operandexpr = ex.Expr 1305 opcode = OP_UNM 1306 case *ast.UnaryNotOpExpr: 1307 switch ex.Expr.(type) { 1308 case *ast.TrueExpr: 1309 code.AddABC(OP_LOADBOOL, savereg(ec, reg), 0, 0, sline(expr)) 1310 return 1311 case *ast.FalseExpr, *ast.NilExpr: 1312 code.AddABC(OP_LOADBOOL, savereg(ec, reg), 1, 0, sline(expr)) 1313 return 1314 default: 1315 opcode = OP_NOT 1316 operandexpr = ex.Expr 1317 } 1318 case *ast.UnaryLenOpExpr: 1319 opcode = OP_LEN 1320 operandexpr = ex.Expr 1321 } 1322 1323 a := savereg(ec, reg) 1324 b := reg 1325 compileExprWithMVPropagation(context, operandexpr, ®, &b) 1326 code.AddABC(opcode, a, b, 0, sline(expr)) 1327 } // }}} 1328 1329 func compileRelationalOpExprAux(context *funcContext, reg int, expr *ast.RelationalOpExpr, flip int, label int) { // {{{ 1330 code := context.Code 1331 b := reg 1332 compileExprWithKMVPropagation(context, expr.Lhs, ®, &b) 1333 c := reg 1334 compileExprWithKMVPropagation(context, expr.Rhs, ®, &c) 1335 switch expr.Operator { 1336 case "<": 1337 code.AddABC(OP_LT, 0^flip, b, c, sline(expr)) 1338 case ">": 1339 code.AddABC(OP_LT, 0^flip, c, b, sline(expr)) 1340 case "<=": 1341 code.AddABC(OP_LE, 0^flip, b, c, sline(expr)) 1342 case ">=": 1343 code.AddABC(OP_LE, 0^flip, c, b, sline(expr)) 1344 case "==": 1345 code.AddABC(OP_EQ, 0^flip, b, c, sline(expr)) 1346 case "~=": 1347 code.AddABC(OP_EQ, 1^flip, b, c, sline(expr)) 1348 } 1349 code.AddASbx(OP_JMP, 0, label, sline(expr)) 1350 } // }}} 1351 1352 func compileRelationalOpExpr(context *funcContext, reg int, expr *ast.RelationalOpExpr, ec *expcontext) { // {{{ 1353 a := savereg(ec, reg) 1354 code := context.Code 1355 jumplabel := context.NewLabel() 1356 compileRelationalOpExprAux(context, reg, expr, 1, jumplabel) 1357 code.AddABC(OP_LOADBOOL, a, 0, 1, sline(expr)) 1358 context.SetLabelPc(jumplabel, code.LastPC()) 1359 code.AddABC(OP_LOADBOOL, a, 1, 0, sline(expr)) 1360 } // }}} 1361 1362 func compileLogicalOpExpr(context *funcContext, reg int, expr *ast.LogicalOpExpr, ec *expcontext) { // {{{ 1363 a := savereg(ec, reg) 1364 code := context.Code 1365 endlabel := context.NewLabel() 1366 lb := &lblabels{context.NewLabel(), context.NewLabel(), endlabel, false} 1367 nextcondlabel := context.NewLabel() 1368 if expr.Operator == "and" { 1369 compileLogicalOpExprAux(context, reg, expr.Lhs, ec, nextcondlabel, endlabel, false, lb) 1370 context.SetLabelPc(nextcondlabel, code.LastPC()) 1371 compileLogicalOpExprAux(context, reg, expr.Rhs, ec, endlabel, endlabel, false, lb) 1372 } else { 1373 compileLogicalOpExprAux(context, reg, expr.Lhs, ec, endlabel, nextcondlabel, true, lb) 1374 context.SetLabelPc(nextcondlabel, code.LastPC()) 1375 compileLogicalOpExprAux(context, reg, expr.Rhs, ec, endlabel, endlabel, false, lb) 1376 } 1377 1378 if lb.b { 1379 context.SetLabelPc(lb.f, code.LastPC()) 1380 code.AddABC(OP_LOADBOOL, a, 0, 1, sline(expr)) 1381 context.SetLabelPc(lb.t, code.LastPC()) 1382 code.AddABC(OP_LOADBOOL, a, 1, 0, sline(expr)) 1383 } 1384 1385 lastinst := code.Last() 1386 if opGetOpCode(lastinst) == OP_JMP && opGetArgSbx(lastinst) == endlabel { 1387 code.Pop() 1388 } 1389 1390 context.SetLabelPc(endlabel, code.LastPC()) 1391 } // }}} 1392 1393 func compileLogicalOpExprAux(context *funcContext, reg int, expr ast.Expr, ec *expcontext, thenlabel, elselabel int, hasnextcond bool, lb *lblabels) { // {{{ 1394 // TODO folding constants? 1395 code := context.Code 1396 flip := 0 1397 jumplabel := elselabel 1398 if hasnextcond { 1399 flip = 1 1400 jumplabel = thenlabel 1401 } 1402 1403 switch ex := expr.(type) { 1404 case *ast.FalseExpr: 1405 if elselabel == lb.e { 1406 code.AddASbx(OP_JMP, 0, lb.f, sline(expr)) 1407 lb.b = true 1408 } else { 1409 code.AddASbx(OP_JMP, 0, elselabel, sline(expr)) 1410 } 1411 return 1412 case *ast.NilExpr: 1413 if elselabel == lb.e { 1414 compileExpr(context, reg, expr, ec) 1415 code.AddASbx(OP_JMP, 0, lb.e, sline(expr)) 1416 } else { 1417 code.AddASbx(OP_JMP, 0, elselabel, sline(expr)) 1418 } 1419 return 1420 case *ast.TrueExpr: 1421 if thenlabel == lb.e { 1422 code.AddASbx(OP_JMP, 0, lb.t, sline(expr)) 1423 lb.b = true 1424 } else { 1425 code.AddASbx(OP_JMP, 0, thenlabel, sline(expr)) 1426 } 1427 return 1428 case *ast.NumberExpr, *ast.StringExpr: 1429 if thenlabel == lb.e { 1430 compileExpr(context, reg, expr, ec) 1431 code.AddASbx(OP_JMP, 0, lb.e, sline(expr)) 1432 } else { 1433 code.AddASbx(OP_JMP, 0, thenlabel, sline(expr)) 1434 } 1435 return 1436 case *ast.LogicalOpExpr: 1437 switch ex.Operator { 1438 case "and": 1439 nextcondlabel := context.NewLabel() 1440 compileLogicalOpExprAux(context, reg, ex.Lhs, ec, nextcondlabel, elselabel, false, lb) 1441 context.SetLabelPc(nextcondlabel, context.Code.LastPC()) 1442 compileLogicalOpExprAux(context, reg, ex.Rhs, ec, thenlabel, elselabel, hasnextcond, lb) 1443 case "or": 1444 nextcondlabel := context.NewLabel() 1445 compileLogicalOpExprAux(context, reg, ex.Lhs, ec, thenlabel, nextcondlabel, true, lb) 1446 context.SetLabelPc(nextcondlabel, context.Code.LastPC()) 1447 compileLogicalOpExprAux(context, reg, ex.Rhs, ec, thenlabel, elselabel, hasnextcond, lb) 1448 } 1449 return 1450 case *ast.RelationalOpExpr: 1451 if thenlabel == elselabel { 1452 flip ^= 1 1453 jumplabel = lb.t 1454 lb.b = true 1455 } else if thenlabel == lb.e { 1456 jumplabel = lb.t 1457 lb.b = true 1458 } else if elselabel == lb.e { 1459 jumplabel = lb.f 1460 lb.b = true 1461 } 1462 compileRelationalOpExprAux(context, reg, ex, flip, jumplabel) 1463 return 1464 } 1465 1466 a := reg 1467 sreg := savereg(ec, a) 1468 if !hasnextcond && thenlabel == elselabel { 1469 reg += compileExpr(context, reg, expr, &expcontext{ec.ctype, intMax(a, sreg), ec.varargopt}) 1470 last := context.Code.Last() 1471 if opGetOpCode(last) == OP_MOVE && opGetArgA(last) == a { 1472 context.Code.SetA(context.Code.LastPC(), sreg) 1473 } else { 1474 context.Code.AddABC(OP_MOVE, sreg, a, 0, sline(expr)) 1475 } 1476 } else { 1477 reg += compileExpr(context, reg, expr, ecnone(0)) 1478 if sreg == a { 1479 code.AddABC(OP_TEST, a, 0, 0^flip, sline(expr)) 1480 } else { 1481 code.AddABC(OP_TESTSET, sreg, a, 0^flip, sline(expr)) 1482 } 1483 } 1484 code.AddASbx(OP_JMP, 0, jumplabel, sline(expr)) 1485 } // }}} 1486 1487 func compileFuncCallExpr(context *funcContext, reg int, expr *ast.FuncCallExpr, ec *expcontext) int { // {{{ 1488 funcreg := reg 1489 if ec.ctype == ecLocal && ec.reg == (int(context.Proto.NumParameters)-1) { 1490 funcreg = ec.reg 1491 reg = ec.reg 1492 } 1493 argc := len(expr.Args) 1494 islastvararg := false 1495 name := "(anonymous)" 1496 1497 if expr.Func != nil { // hoge.func() 1498 reg += compileExpr(context, reg, expr.Func, ecnone(0)) 1499 name = getExprName(context, expr.Func) 1500 } else { // hoge:method() 1501 b := reg 1502 compileExprWithMVPropagation(context, expr.Receiver, ®, &b) 1503 c := loadRk(context, ®, expr, LString(expr.Method)) 1504 context.Code.AddABC(OP_SELF, funcreg, b, c, sline(expr)) 1505 // increments a register for an implicit "self" 1506 reg = b + 1 1507 reg2 := funcreg + 2 1508 if reg2 > reg { 1509 reg = reg2 1510 } 1511 argc += 1 1512 name = string(expr.Method) 1513 } 1514 1515 for i, ar := range expr.Args { 1516 islastvararg = (i == len(expr.Args)-1) && isVarArgReturnExpr(ar) 1517 if islastvararg { 1518 compileExpr(context, reg, ar, ecnone(-2)) 1519 } else { 1520 reg += compileExpr(context, reg, ar, ecnone(0)) 1521 } 1522 } 1523 b := argc + 1 1524 if islastvararg { 1525 b = 0 1526 } 1527 context.Code.AddABC(OP_CALL, funcreg, b, ec.varargopt+2, sline(expr)) 1528 context.Proto.DbgCalls = append(context.Proto.DbgCalls, DbgCall{Pc: context.Code.LastPC(), Name: name}) 1529 1530 if ec.varargopt == 0 && shouldmove(ec, funcreg) { 1531 context.Code.AddABC(OP_MOVE, ec.reg, funcreg, 0, sline(expr)) 1532 return 1 1533 } 1534 if context.RegTop() > (funcreg+2+ec.varargopt) || ec.varargopt < -1 { 1535 return 0 1536 } 1537 return ec.varargopt + 1 1538 } // }}} 1539 1540 func loadRk(context *funcContext, reg *int, expr ast.Expr, cnst LValue) int { // {{{ 1541 cindex := context.ConstIndex(cnst) 1542 if cindex <= opMaxIndexRk { 1543 return opRkAsk(cindex) 1544 } else { 1545 ret := *reg 1546 *reg++ 1547 context.Code.AddABx(OP_LOADK, ret, cindex, sline(expr)) 1548 return ret 1549 } 1550 } // }}} 1551 1552 func getIdentRefType(context *funcContext, current *funcContext, expr *ast.IdentExpr) expContextType { // {{{ 1553 if current == nil { 1554 return ecGlobal 1555 } else if current.FindLocalVar(expr.Value) > -1 { 1556 if current == context { 1557 return ecLocal 1558 } 1559 return ecUpvalue 1560 } 1561 return getIdentRefType(context, current.Parent, expr) 1562 } // }}} 1563 1564 func getExprName(context *funcContext, expr ast.Expr) string { // {{{ 1565 switch ex := expr.(type) { 1566 case *ast.IdentExpr: 1567 return ex.Value 1568 case *ast.AttrGetExpr: 1569 switch kex := ex.Key.(type) { 1570 case *ast.StringExpr: 1571 return kex.Value 1572 } 1573 return "?" 1574 } 1575 return "?" 1576 } // }}} 1577 1578 func patchCode(context *funcContext) { // {{{ 1579 maxreg := 1 1580 if np := int(context.Proto.NumParameters); np > 1 { 1581 maxreg = np 1582 } 1583 moven := 0 1584 code := context.Code.List() 1585 for pc := 0; pc < len(code); pc++ { 1586 inst := code[pc] 1587 curop := opGetOpCode(inst) 1588 switch curop { 1589 case OP_CLOSURE: 1590 pc += int(context.Proto.FunctionPrototypes[opGetArgBx(inst)].NumUpvalues) 1591 moven = 0 1592 continue 1593 case OP_SETGLOBAL, OP_SETUPVAL, OP_EQ, OP_LT, OP_LE, OP_TEST, 1594 OP_TAILCALL, OP_RETURN, OP_FORPREP, OP_FORLOOP, OP_TFORLOOP, 1595 OP_SETLIST, OP_CLOSE: 1596 /* nothing to do */ 1597 case OP_CALL: 1598 if reg := opGetArgA(inst) + opGetArgC(inst) - 2; reg > maxreg { 1599 maxreg = reg 1600 } 1601 case OP_VARARG: 1602 if reg := opGetArgA(inst) + opGetArgB(inst) - 1; reg > maxreg { 1603 maxreg = reg 1604 } 1605 case OP_SELF: 1606 if reg := opGetArgA(inst) + 1; reg > maxreg { 1607 maxreg = reg 1608 } 1609 case OP_LOADNIL: 1610 if reg := opGetArgB(inst); reg > maxreg { 1611 maxreg = reg 1612 } 1613 case OP_JMP: // jump to jump optimization 1614 distance := 0 1615 count := 0 // avoiding infinite loops 1616 for jmp := inst; opGetOpCode(jmp) == OP_JMP && count < 5; jmp = context.Code.At(pc + distance + 1) { 1617 d := context.GetLabelPc(opGetArgSbx(jmp)) - pc 1618 if d > opMaxArgSbx { 1619 if distance == 0 { 1620 raiseCompileError(context, context.Proto.LineDefined, "too long to jump.") 1621 } 1622 break 1623 } 1624 distance = d 1625 count++ 1626 } 1627 if distance == 0 { 1628 context.Code.SetOpCode(pc, OP_NOP) 1629 } else { 1630 context.Code.SetSbx(pc, distance) 1631 } 1632 default: 1633 if reg := opGetArgA(inst); reg > maxreg { 1634 maxreg = reg 1635 } 1636 } 1637 1638 // bulk move optimization(reducing op dipatch costs) 1639 if curop == OP_MOVE { 1640 moven++ 1641 } else { 1642 if moven > 1 { 1643 context.Code.SetOpCode(pc-moven, OP_MOVEN) 1644 context.Code.SetC(pc-moven, intMin(moven-1, opMaxArgsC)) 1645 } 1646 moven = 0 1647 } 1648 } 1649 maxreg++ 1650 if maxreg > maxRegisters { 1651 raiseCompileError(context, context.Proto.LineDefined, "register overflow(too many local variables)") 1652 } 1653 context.Proto.NumUsedRegisters = uint8(maxreg) 1654 } // }}} 1655 1656 func Compile(chunk []ast.Stmt, name string) (proto *FunctionProto, err error) { // {{{ 1657 defer func() { 1658 if rcv := recover(); rcv != nil { 1659 if _, ok := rcv.(*CompileError); ok { 1660 err = rcv.(error) 1661 } else { 1662 panic(rcv) 1663 } 1664 } 1665 }() 1666 err = nil 1667 parlist := &ast.ParList{HasVargs: true, Names: []string{}} 1668 funcexpr := &ast.FunctionExpr{ParList: parlist, Stmts: chunk} 1669 context := newFuncContext(name, nil) 1670 compileFunctionExpr(context, funcexpr, ecnone(0)) 1671 proto = context.Proto 1672 return 1673 } // }}}