github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/compiler/codegen/gen_stmt.go (about) 1 package codegen 2 3 import ( 4 "fmt" 5 6 "github.com/hirochachacha/plua/compiler/ast" 7 "github.com/hirochachacha/plua/compiler/token" 8 "github.com/hirochachacha/plua/internal/version" 9 "github.com/hirochachacha/plua/object" 10 "github.com/hirochachacha/plua/opcode" 11 ) 12 13 type immBool int 14 15 const ( 16 immUndefined immBool = iota 17 immTrue 18 immFalse 19 ) 20 21 func (g *generator) genStmt(stmt ast.Stmt) { 22 switch stmt := stmt.(type) { 23 case *ast.BadStmt: 24 panic("bad stmt") 25 case *ast.EmptyStmt: 26 // do nothing 27 case *ast.LocalAssignStmt: 28 g.genLocalAssignStmt(stmt) 29 case *ast.LocalFuncStmt: 30 g.genLocalFuncStmt(stmt) 31 case *ast.FuncStmt: 32 g.genFuncStmt(stmt) 33 case *ast.LabelStmt: 34 g.genLabelStmt(stmt) 35 case *ast.ExprStmt: 36 g.genExprStmt(stmt) 37 case *ast.AssignStmt: 38 g.genAssignStmt(stmt) 39 case *ast.GotoStmt: 40 g.genGotoStmt(stmt) 41 case *ast.BreakStmt: 42 g.genBreakStmt(stmt) 43 case *ast.IfStmt: 44 g.genIfStmt(stmt) 45 case *ast.DoStmt: 46 g.genDoStmt(stmt) 47 case *ast.WhileStmt: 48 g.genWhileStmt(stmt) 49 case *ast.RepeatStmt: 50 g.genRepeatStmt(stmt) 51 case *ast.ReturnStmt: 52 g.genReturnStmt(stmt) 53 case *ast.ForStmt: 54 g.genForStmt(stmt) 55 case *ast.ForEachStmt: 56 g.genForEachStmt(stmt) 57 default: 58 panic("unreachable") 59 } 60 } 61 62 func (g *generator) genLocalAssignStmt(stmt *ast.LocalAssignStmt) { 63 sp := g.sp 64 65 g.locktmp = true 66 67 switch { 68 case len(stmt.LHS) > len(stmt.RHS): 69 if len(stmt.RHS) == 0 { 70 g.pushInst(opcode.AB(opcode.LOADNIL, g.sp, len(stmt.LHS)-1)) 71 } else { 72 for _, e := range stmt.RHS[:len(stmt.RHS)-1] { 73 g.genExpr(e, genMove) 74 } 75 76 g.genExprN(stmt.RHS[len(stmt.RHS)-1], len(stmt.LHS)+1-len(stmt.RHS)) 77 } 78 case len(stmt.LHS) < len(stmt.RHS): 79 for i := range stmt.LHS { 80 g.genExpr(stmt.RHS[i], genMove) 81 } 82 83 for i := len(stmt.LHS); i < len(stmt.RHS); i++ { 84 if _, ok := g.foldExpr(stmt.RHS[i]); !ok { 85 g.genExprN(stmt.RHS[i], 0) 86 } 87 } 88 default: 89 for i := range stmt.LHS { 90 g.genExpr(stmt.RHS[i], genMove) 91 } 92 } 93 94 g.locktmp = false 95 96 for i, name := range stmt.LHS { 97 g.declareLocalName(name, sp+i) 98 } 99 100 g.setSP(sp + len(stmt.LHS)) 101 } 102 103 func (g *generator) genLocalFuncStmt(stmt *ast.LocalFuncStmt) { 104 name := stmt.Name 105 106 body := stmt.Body 107 108 endLine := stmt.End().Line 109 110 g.declareLocalName(name, g.sp) // declare before genFuncBody (for recursive function) 111 112 p := g.proto(body, false, endLine) 113 114 g.pushInstLine(opcode.ABx(opcode.CLOSURE, g.sp, p), endLine) 115 116 g.LocVars[len(g.LocVars)-1].StartPC++ // adjust StartPC (start from CLOSURE) 117 118 g.nextSP() 119 } 120 121 func (g *generator) genFuncStmt(stmt *ast.FuncStmt) { 122 sp := g.sp 123 124 name := stmt.Name 125 prefix := stmt.PathList 126 127 body := stmt.Body 128 129 endLine := stmt.End().Line 130 131 if prefix == nil { 132 l, ok := g.resolveName(name) 133 134 p := g.proto(body, false, endLine) 135 136 if ok { 137 switch l.kind { 138 case linkLocal: 139 g.pushInstLine(opcode.ABx(opcode.CLOSURE, l.index, p), endLine) 140 case linkUpval: 141 g.pushInstLine(opcode.ABx(opcode.CLOSURE, g.sp, p), endLine) 142 143 g.pushInst(opcode.AB(opcode.SETUPVAL, g.sp, l.index)) 144 default: 145 panic("unreachable") 146 } 147 } else { 148 g.pushInstLine(opcode.ABx(opcode.CLOSURE, g.sp, p), endLine) 149 150 g.genSetGlobal(name, g.sp) 151 } 152 } else { 153 r := g.genPrefix(prefix) 154 155 rk := g.genName(name, genKey) 156 157 switch stmt.AccessTok { 158 case token.COLON: 159 p := g.proto(body, true, endLine) 160 161 g.pushInstLine(opcode.ABx(opcode.CLOSURE, g.sp, p), endLine) 162 163 g.pushInst(opcode.ABC(opcode.SETTABLE, r, rk, g.sp)) 164 case token.PERIOD: 165 p := g.proto(body, false, endLine) 166 167 g.pushInstLine(opcode.ABx(opcode.CLOSURE, g.sp, p), endLine) 168 169 g.pushInst(opcode.ABC(opcode.SETTABLE, r, rk, g.sp)) 170 default: 171 panic("unreachable") 172 } 173 } 174 175 // recover sp 176 g.sp = sp 177 } 178 179 func (g *generator) genLabelStmt(stmt *ast.LabelStmt) { 180 nameNode := stmt.Name 181 name := nameNode.Name 182 pos := nameNode.Pos() 183 184 if label, ok := g.labels[name]; ok { 185 g.error(pos, fmt.Errorf("label '%s' already defined on %s", name, label.pos)) 186 } 187 188 g.declareLabelPos(name, pos) 189 190 g.lockpeep = true 191 } 192 193 func (g *generator) genExprStmt(stmt *ast.ExprStmt) { 194 sp := g.sp 195 196 g.genExprN(stmt.X, 0) 197 198 // recover sp 199 g.sp = sp 200 } 201 202 func (g *generator) genAssignStmt(stmt *ast.AssignStmt) { 203 sp := g.sp 204 205 g.locktmp = true 206 207 switch { 208 case len(stmt.LHS) > len(stmt.RHS): 209 if len(stmt.RHS) == 0 { 210 g.pushInst(opcode.AB(opcode.LOADNIL, sp, len(stmt.LHS)-1)) 211 } else { 212 for _, e := range stmt.RHS[:len(stmt.RHS)-1] { 213 g.genExpr(e, genMove) 214 } 215 216 g.genExprN(stmt.RHS[len(stmt.RHS)-1], len(stmt.LHS)+1-len(stmt.RHS)) 217 } 218 case len(stmt.LHS) < len(stmt.RHS): 219 for i := range stmt.LHS { 220 g.genExpr(stmt.RHS[i], genMove) 221 } 222 223 for i := len(stmt.LHS); i < len(stmt.RHS); i++ { 224 if _, ok := g.foldExpr(stmt.RHS[i]); !ok { 225 g.genExprN(stmt.RHS[i], 0) 226 } 227 } 228 default: 229 for i := range stmt.LHS { 230 g.genExpr(stmt.RHS[i], genMove) 231 } 232 } 233 234 g.locktmp = false 235 236 if len(stmt.LHS) == 1 { // fast path 237 g.genAssignSimple(stmt.LHS[0], sp) 238 } else { 239 g.genAssign(stmt.LHS, sp) 240 } 241 242 g.sp = sp 243 } 244 245 func (g *generator) genAssignSimple(lhs ast.Expr, r int) { 246 switch lhs := lhs.(type) { 247 case *ast.Name: 248 if l, ok := g.resolveName(lhs); ok { 249 switch l.kind { 250 case linkLocal: 251 g.pushInst(opcode.AB(opcode.MOVE, l.index, r)) 252 case linkUpval: 253 g.pushInst(opcode.AB(opcode.SETUPVAL, r, l.index)) 254 default: 255 panic("unreachable") 256 } 257 } else { 258 g.genSetGlobal(lhs, r) 259 } 260 case *ast.SelectorExpr: 261 x := g.genExpr(lhs.X, genR|genK) 262 y := g.genName(lhs.Sel, genKey) 263 264 g.pushInst(opcode.ABC(opcode.SETTABLE, x, y, r)) 265 case *ast.IndexExpr: 266 x := g.genExpr(lhs.X, genR|genK) 267 y := g.genExpr(lhs.Index, genR|genK) 268 269 g.pushInst(opcode.ABC(opcode.SETTABLE, x, y, r)) 270 default: 271 panic("unreachable") 272 } 273 } 274 275 func (g *generator) genAssign(LHS []ast.Expr, base int) { 276 assigns := make([]opcode.Instruction, len(LHS)) 277 278 g.locktmp = true 279 280 var r int 281 for i, lhs := range LHS { 282 r = base + i 283 284 switch lhs := lhs.(type) { 285 case *ast.Name: 286 if l, ok := g.resolveName(lhs); ok { 287 switch l.kind { 288 case linkLocal: 289 assigns[i] = opcode.AB(opcode.MOVE, l.index, r) 290 case linkUpval: 291 assigns[i] = opcode.AB(opcode.SETUPVAL, r, l.index) 292 default: 293 panic("unreachable") 294 } 295 } else { 296 env := g.genName(tmpName(version.LUA_ENV), genR|genMove) 297 298 rk := g.markRK(g.constant(object.String(lhs.Name)), false) 299 300 assigns[i] = opcode.ABC(opcode.SETTABLE, env, rk, r) 301 } 302 case *ast.SelectorExpr: 303 x := g.genExpr(lhs.X, genR|genK|genMove) 304 y := g.genName(lhs.Sel, genKey) 305 306 assigns[i] = opcode.ABC(opcode.SETTABLE, x, y, r) 307 case *ast.IndexExpr: 308 x := g.genExpr(lhs.X, genR|genK|genMove) 309 y := g.genExpr(lhs.Index, genR|genK|genMove) 310 311 assigns[i] = opcode.ABC(opcode.SETTABLE, x, y, r) 312 default: 313 panic("unreachable") 314 } 315 } 316 317 for _, assign := range assigns[:len(assigns)-1] { 318 g.pushInst(assign) 319 } 320 321 g.locktmp = false 322 323 g.pushInst(assigns[len(assigns)-1]) 324 } 325 326 func (g *generator) genGotoStmt(stmt *ast.GotoStmt) { 327 g.genSetJumpPoint(stmt.Label.Name, stmt.Label.Pos()) 328 } 329 330 func (g *generator) genBreakStmt(stmt *ast.BreakStmt) { 331 g.genSetJumpPoint("@break", stmt.Break) 332 } 333 334 func (g *generator) genIfStmt(stmt *ast.IfStmt) { 335 if stmt.ElseIfList != nil { 336 elseBody := stmt.ElseBody 337 root := &ast.IfStmt{ 338 Cond: stmt.Cond, 339 Body: stmt.Body, 340 } 341 leaf := root 342 for _, stmt := range stmt.ElseIfList { 343 nextLeaf := &ast.IfStmt{ 344 Cond: stmt.Cond, 345 Body: stmt.Body, 346 } 347 leaf.ElseBody = &ast.Block{ 348 List: []ast.Stmt{ 349 nextLeaf, 350 }, 351 } 352 leaf = nextLeaf 353 } 354 leaf.ElseBody = elseBody 355 stmt = root 356 } 357 358 g.openScope() 359 360 switch g.genTest(stmt.Cond, false) { 361 case immTrue: 362 if stmt.Body != nil { 363 g.genBlock(stmt.Body) 364 } 365 case immFalse: 366 if stmt.ElseBody != nil { 367 g.genBlock(stmt.ElseBody) 368 } 369 default: 370 elseJump := g.genJumpPoint() 371 372 if stmt.Body != nil { 373 g.openScope() 374 375 g.genBlock(stmt.Body) 376 377 g.closeScope() 378 } 379 380 if stmt.ElseBody != nil { 381 doneJump := g.genJumpPoint() 382 383 g.genJumpFrom(elseJump) 384 385 g.openScope() 386 387 g.genBlock(stmt.ElseBody) 388 389 g.closeScope() 390 391 g.genJumpFrom(doneJump) 392 } else { 393 g.genJumpFrom(elseJump) 394 } 395 } 396 397 g.closeScope() 398 } 399 400 func (g *generator) genDoStmt(stmt *ast.DoStmt) { 401 if stmt.Body != nil { 402 g.openScope() 403 404 g.genBlock(stmt.Body) 405 406 g.closeScope() 407 } 408 } 409 410 func (g *generator) genWhileStmt(stmt *ast.WhileStmt) { 411 g.openScope() 412 413 initLabel := g.newLabel() 414 415 switch g.genTest(stmt.Cond, false) { 416 case immTrue: 417 if stmt.Body != nil { 418 g.genBlock(stmt.Body) 419 } 420 421 g.closeScope() 422 423 g.genJumpTo(initLabel) 424 425 g.declareLabel("@break") 426 case immFalse: 427 g.closeScope() 428 default: 429 endJump := g.genJumpPoint() 430 431 if stmt.Body != nil { 432 g.genBlock(stmt.Body) 433 } 434 435 g.closeScope() 436 437 g.genJumpTo(initLabel) 438 439 g.genJumpFrom(endJump) 440 441 g.declareLabel("@break") 442 } 443 } 444 445 func (g *generator) genRepeatStmt(stmt *ast.RepeatStmt) { 446 g.openScope() 447 448 initLabel := g.newLabel() 449 450 if stmt.Body != nil { 451 g.genBlock(stmt.Body) 452 } 453 454 switch g.genTest(stmt.Cond, true) { 455 case immTrue: 456 g.genJumpTo(initLabel) 457 458 g.declareLabel("@break") 459 case immFalse: 460 g.declareLabel("@break") 461 default: 462 endJump := g.genJumpPoint() 463 464 g.genJumpTo(initLabel) 465 466 g.genJumpFrom(endJump) 467 468 g.declareLabel("@break") 469 } 470 471 g.closeScope() 472 } 473 474 func (g *generator) genReturnStmt(stmt *ast.ReturnStmt) { 475 if len(stmt.Results) == 0 { 476 g.pushInst(opcode.AB(opcode.RETURN, 0, 1)) 477 478 return 479 } 480 481 sp := g.sp 482 483 if len(stmt.Results) == 1 { 484 if tail, ok := stmt.Results[len(stmt.Results)-1].(*ast.CallExpr); ok { 485 g.genCallExprN(tail, -1, true) 486 487 g.pushInst(opcode.AB(opcode.RETURN, sp, 0)) 488 489 return 490 } 491 } 492 493 g.locktmp = true 494 495 var isVar bool 496 if len(stmt.Results) != 0 { 497 for _, e := range stmt.Results[:len(stmt.Results)-1] { 498 g.genExpr(e, genMove) 499 } 500 501 isVar = g.genExprN(stmt.Results[len(stmt.Results)-1], -1) 502 } 503 504 if isVar { 505 g.pushInst(opcode.AB(opcode.RETURN, sp, 0)) 506 } else { 507 g.pushInst(opcode.AB(opcode.RETURN, sp, len(stmt.Results)+1)) 508 } 509 510 g.locktmp = false 511 } 512 513 func (g *generator) genForStmt(stmt *ast.ForStmt) { 514 g.openScope() 515 516 forLine := stmt.For.Line 517 518 sp := g.sp 519 520 g.locktmp = true 521 522 g.genExpr(stmt.Start, genMove) 523 g.genExpr(stmt.Finish, genMove) 524 if stmt.Step != nil { 525 g.genExpr(stmt.Step, genMove) 526 } else { 527 g.genConst(object.Integer(1), genMove) 528 } 529 530 g.locktmp = false 531 532 g.declareLocal("(for index)", sp) 533 g.declareLocal("(for limit)", sp+1) 534 g.declareLocal("(for step)", sp+2) 535 536 forprep := g.pushTempLine(forLine) 537 538 g.openScope() 539 540 g.declareLocalName(stmt.Name, g.sp) 541 542 g.addSP(1) 543 544 if stmt.Body != nil { 545 g.genBlock(stmt.Body) 546 } 547 548 g.closeScope() 549 550 g.Code[forprep] = opcode.AsBx(opcode.FORPREP, sp, g.pc()-forprep-1) 551 552 g.pushInstLine(opcode.AsBx(opcode.FORLOOP, sp, forprep-g.pc()), forLine) 553 554 g.declareLabel("@break") 555 556 g.sp = sp 557 558 g.closeScope() 559 } 560 561 func (g *generator) genForEachStmt(stmt *ast.ForEachStmt) { 562 g.openScope() 563 564 forLine := stmt.For.Line 565 566 sp := g.sp 567 568 g.locktmp = true 569 570 switch { 571 case len(stmt.Exprs) > 3: 572 g.genExpr(stmt.Exprs[0], genMove) 573 g.genExpr(stmt.Exprs[1], genMove) 574 g.genExpr(stmt.Exprs[2], genMove) 575 for i := 3; i < len(stmt.Exprs); i++ { 576 if _, ok := g.foldExpr(stmt.Exprs[i]); !ok { 577 g.genExprN(stmt.Exprs[i], 0) 578 } 579 } 580 case len(stmt.Exprs) < 3: 581 switch len(stmt.Exprs) { 582 case 1: 583 g.genExprN(stmt.Exprs[0], 3) 584 case 2: 585 g.genExpr(stmt.Exprs[0], genMove) 586 g.genExprN(stmt.Exprs[1], 2) 587 default: 588 panic("unreachable") 589 } 590 default: 591 for _, e := range stmt.Exprs { 592 g.genExpr(e, genMove) 593 } 594 } 595 596 g.locktmp = false 597 598 g.declareLocal("(for generator)", sp) 599 g.declareLocal("(for generator)", sp+1) 600 g.declareLocal("(for control)", sp+2) 601 602 g.setSP(sp + 3) 603 604 loopJump := g.genJumpPoint() 605 606 g.openScope() 607 608 for i, name := range stmt.Names { 609 g.declareLocalName(name, g.sp+i) 610 } 611 612 g.addSP(len(stmt.Names)) 613 614 init := g.pc() 615 616 if stmt.Body != nil { 617 g.genBlock(stmt.Body) 618 } 619 620 g.genJumpFrom(loopJump) 621 622 g.closeScope() 623 624 g.pushInstLine(opcode.AC(opcode.TFORCALL, sp, len(stmt.Names)), forLine) 625 626 g.pushInstLine(opcode.AsBx(opcode.TFORLOOP, sp+2, init-g.pc()-1), forLine) 627 628 g.declareLabel("@break") 629 630 g.closeScope() 631 }