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