github.com/goplus/gox@v1.14.13-0.20240308130321-6ff7f61cfae8/codebuild.go (about) 1 /* 2 Copyright 2021 The GoPlus Authors (goplus.org) 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package gox 15 16 import ( 17 "errors" 18 "fmt" 19 "go/ast" 20 "go/constant" 21 "go/token" 22 "go/types" 23 "log" 24 "math/big" 25 "reflect" 26 "strconv" 27 "strings" 28 "syscall" 29 30 "github.com/goplus/gox/internal" 31 xtoken "github.com/goplus/gox/token" 32 "golang.org/x/tools/go/types/typeutil" 33 ) 34 35 func getSrc(node []ast.Node) ast.Node { 36 if node != nil { 37 return node[0] 38 } 39 return nil 40 } 41 42 func getSrcPos(node ast.Node) token.Pos { 43 if node != nil { 44 return node.Pos() 45 } 46 return token.NoPos 47 } 48 49 func getPos(src []ast.Node) token.Pos { 50 if src == nil { 51 return token.NoPos 52 } 53 return getSrcPos(src[0]) 54 } 55 56 // ---------------------------------------------------------------------------- 57 58 type posNode struct { 59 pos, end token.Pos 60 } 61 62 func NewPosNode(pos token.Pos, end ...token.Pos) ast.Node { 63 ret := &posNode{pos: pos, end: pos} 64 if end != nil { 65 ret.end = end[0] 66 } 67 return ret 68 } 69 70 func (p *posNode) Pos() token.Pos { return p.pos } 71 func (p *posNode) End() token.Pos { return p.end } 72 73 // ---------------------------------------------------------------------------- 74 75 type codeBlock interface { 76 End(cb *CodeBuilder, src ast.Node) 77 } 78 79 type vblockCtx struct { 80 codeBlock 81 scope *types.Scope 82 } 83 84 type codeBlockCtx struct { 85 codeBlock 86 scope *types.Scope 87 base int 88 stmts []ast.Stmt 89 label *ast.LabeledStmt 90 flows int // flow flags 91 } 92 93 const ( 94 flowFlagBreak = 1 << iota 95 flowFlagContinue 96 flowFlagReturn 97 flowFlagGoto 98 flowFlagWithLabel 99 ) 100 101 type Label struct { 102 types.Label 103 used bool 104 } 105 106 type funcBodyCtx struct { 107 codeBlockCtx 108 fn *Func 109 labels map[string]*Label 110 } 111 112 func (p *funcBodyCtx) checkLabels(cb *CodeBuilder) { 113 for name, l := range p.labels { 114 if !l.used { 115 cb.handleCodeErrorf(l.Pos(), "label %s defined and not used", name) 116 } 117 } 118 } 119 120 type CodeError struct { 121 Fset dbgPositioner 122 Pos token.Pos 123 Msg string 124 } 125 126 func (p *CodeError) Error() string { 127 pos := p.Fset.Position(p.Pos) 128 return fmt.Sprintf("%v: %s", pos, p.Msg) 129 } 130 131 // CodeBuilder type 132 type CodeBuilder struct { 133 stk internal.Stack 134 current funcBodyCtx 135 fset dbgPositioner 136 comments *ast.CommentGroup 137 pkg *Package 138 btiMap *typeutil.Map 139 valDecl *ValueDecl 140 ctxt *typesContext 141 interp NodeInterpreter 142 rec Recorder 143 loadNamed LoadNamedFunc 144 handleErr func(err error) 145 closureParamInsts 146 vFieldsMgr 147 iotav int 148 commentOnce bool 149 noSkipConst bool 150 } 151 152 func (p *CodeBuilder) init(pkg *Package) { 153 conf := pkg.conf 154 p.pkg = pkg 155 p.fset = conf.DbgPositioner 156 if p.fset == nil { 157 p.fset = conf.Fset 158 } 159 p.noSkipConst = conf.NoSkipConstant 160 p.handleErr = conf.HandleErr 161 if p.handleErr == nil { 162 p.handleErr = defaultHandleErr 163 } 164 p.rec = conf.Recorder 165 p.interp = conf.NodeInterpreter 166 if p.interp == nil { 167 p.interp = nodeInterp{} 168 } 169 p.ctxt = newTypesContext() 170 p.loadNamed = conf.LoadNamed 171 if p.loadNamed == nil { 172 p.loadNamed = defaultLoadNamed 173 } 174 p.current.scope = pkg.Types.Scope() 175 p.stk.Init() 176 p.closureParamInsts.init() 177 } 178 179 func defaultLoadNamed(at *Package, t *types.Named) { 180 // no delay-loaded named types 181 } 182 183 func defaultHandleErr(err error) { 184 panic(err) 185 } 186 187 type nodeInterp struct{} 188 189 func (p nodeInterp) LoadExpr(expr ast.Node) string { 190 return "" 191 } 192 193 func getFunExpr(fn *internal.Elem) (caller string, pos token.Pos) { 194 if fn == nil { 195 return "the closure call", token.NoPos 196 } 197 caller = types.ExprString(fn.Val) 198 pos = getSrcPos(fn.Src) 199 return 200 } 201 202 func getCaller(expr *internal.Elem) string { 203 if ce, ok := expr.Val.(*ast.CallExpr); ok { 204 return types.ExprString(ce.Fun) 205 } 206 return "the function call" 207 } 208 209 func (p *CodeBuilder) loadExpr(expr ast.Node) (string, token.Pos) { 210 if expr == nil { 211 return "", token.NoPos 212 } 213 return p.interp.LoadExpr(expr), expr.Pos() 214 } 215 216 func (p *CodeBuilder) newCodeError(pos token.Pos, msg string) *CodeError { 217 return &CodeError{Msg: msg, Pos: pos, Fset: p.fset} 218 } 219 220 func (p *CodeBuilder) newCodeErrorf(pos token.Pos, format string, args ...interface{}) *CodeError { 221 return p.newCodeError(pos, fmt.Sprintf(format, args...)) 222 } 223 224 func (p *CodeBuilder) handleCodeError(pos token.Pos, msg string) { 225 p.handleErr(p.newCodeError(pos, msg)) 226 } 227 228 func (p *CodeBuilder) handleCodeErrorf(pos token.Pos, format string, args ...interface{}) { 229 p.handleErr(p.newCodeError(pos, fmt.Sprintf(format, args...))) 230 } 231 232 func (p *CodeBuilder) panicCodeError(pos token.Pos, msg string) { 233 panic(p.newCodeError(pos, msg)) 234 } 235 236 func (p *CodeBuilder) panicCodeErrorf(pos token.Pos, format string, args ...interface{}) { 237 panic(p.newCodeError(pos, fmt.Sprintf(format, args...))) 238 } 239 240 // Scope returns current scope. 241 func (p *CodeBuilder) Scope() *types.Scope { 242 return p.current.scope 243 } 244 245 // Func returns current func (nil means in global scope). 246 func (p *CodeBuilder) Func() *Func { 247 return p.current.fn 248 } 249 250 // Pkg returns the package instance. 251 func (p *CodeBuilder) Pkg() *Package { 252 return p.pkg 253 } 254 255 func (p *CodeBuilder) startFuncBody(fn *Func, src []ast.Node, old *funcBodyCtx) *CodeBuilder { 256 p.current.fn, old.fn = fn, p.current.fn 257 p.current.labels, old.labels = nil, p.current.labels 258 p.startBlockStmt(fn, src, "func "+fn.Name(), &old.codeBlockCtx) 259 scope := p.current.scope 260 sig := fn.Type().(*types.Signature) 261 insertParams(scope, sig.Params()) 262 insertParams(scope, sig.Results()) 263 if recv := sig.Recv(); recv != nil { 264 scope.Insert(recv) 265 } 266 return p 267 } 268 269 func insertParams(scope *types.Scope, params *types.Tuple) { 270 for i, n := 0, params.Len(); i < n; i++ { 271 v := params.At(i) 272 if name := v.Name(); name != "" && name != "_" { 273 scope.Insert(v) 274 } 275 } 276 } 277 278 func (p *CodeBuilder) endFuncBody(old funcBodyCtx) []ast.Stmt { 279 p.current.checkLabels(p) 280 p.current.fn = old.fn 281 p.current.labels = old.labels 282 stmts, _ := p.endBlockStmt(&old.codeBlockCtx) 283 return stmts 284 } 285 286 func (p *CodeBuilder) startBlockStmt(current codeBlock, src []ast.Node, comment string, old *codeBlockCtx) *CodeBuilder { 287 var start, end token.Pos 288 if src != nil { 289 start, end = src[0].Pos(), src[0].End() 290 } 291 scope := types.NewScope(p.current.scope, start, end, comment) 292 p.current.codeBlockCtx, *old = codeBlockCtx{current, scope, p.stk.Len(), nil, nil, 0}, p.current.codeBlockCtx 293 return p 294 } 295 296 func (p *CodeBuilder) endBlockStmt(old *codeBlockCtx) ([]ast.Stmt, int) { 297 flows := p.current.flows 298 if p.current.label != nil { 299 p.emitStmt(&ast.EmptyStmt{}) 300 } 301 stmts := p.current.stmts 302 p.stk.SetLen(p.current.base) 303 p.current.codeBlockCtx = *old 304 return stmts, flows 305 } 306 307 func (p *CodeBuilder) clearBlockStmt() []ast.Stmt { 308 stmts := p.current.stmts 309 p.current.stmts = nil 310 return stmts 311 } 312 313 func (p *CodeBuilder) startVBlockStmt(current codeBlock, comment string, old *vblockCtx) *CodeBuilder { 314 *old = vblockCtx{codeBlock: p.current.codeBlock, scope: p.current.scope} 315 scope := types.NewScope(p.current.scope, token.NoPos, token.NoPos, comment) 316 p.current.codeBlock, p.current.scope = current, scope 317 return p 318 } 319 320 func (p *CodeBuilder) endVBlockStmt(old *vblockCtx) { 321 p.current.codeBlock, p.current.scope = old.codeBlock, old.scope 322 } 323 324 func (p *CodeBuilder) popStmt() ast.Stmt { 325 stmts := p.current.stmts 326 n := len(stmts) - 1 327 stmt := stmts[n] 328 p.current.stmts = stmts[:n] 329 return stmt 330 } 331 332 func (p *CodeBuilder) startStmtAt(stmt ast.Stmt) int { 333 idx := len(p.current.stmts) 334 p.emitStmt(stmt) 335 return idx 336 } 337 338 // Usage: 339 // 340 // idx := cb.startStmtAt(stmt) 341 // ... 342 // cb.commitStmt(idx) 343 func (p *CodeBuilder) commitStmt(idx int) { 344 stmts := p.current.stmts 345 n := len(stmts) - 1 346 if n > idx { 347 stmt := stmts[idx] 348 copy(stmts[idx:], stmts[idx+1:]) 349 stmts[n] = stmt 350 } 351 } 352 353 func (p *CodeBuilder) emitStmt(stmt ast.Stmt) { 354 if p.comments != nil { 355 p.pkg.setStmtComments(stmt, p.comments) 356 if p.commentOnce { 357 p.comments = nil 358 } 359 } 360 if p.current.label != nil { 361 p.current.label.Stmt = stmt 362 stmt, p.current.label = p.current.label, nil 363 } 364 p.current.stmts = append(p.current.stmts, stmt) 365 } 366 367 func (p *CodeBuilder) startInitExpr(current codeBlock) (old codeBlock) { 368 p.current.codeBlock, old = current, p.current.codeBlock 369 return 370 } 371 372 func (p *CodeBuilder) endInitExpr(old codeBlock) { 373 p.current.codeBlock = old 374 } 375 376 // Comments returns the comments of next statement. 377 func (p *CodeBuilder) Comments() *ast.CommentGroup { 378 return p.comments 379 } 380 381 func (p *CodeBuilder) BackupComments() (*ast.CommentGroup, bool) { 382 return p.comments, p.commentOnce 383 } 384 385 // SetComments sets comments to next statement. 386 func (p *CodeBuilder) SetComments(comments *ast.CommentGroup, once bool) *CodeBuilder { 387 if debugComments && comments != nil { 388 for i, c := range comments.List { 389 log.Println("SetComments", i, c.Text) 390 } 391 } 392 p.comments, p.commentOnce = comments, once 393 return p 394 } 395 396 // ReturnErr func 397 func (p *CodeBuilder) ReturnErr(outer bool) *CodeBuilder { 398 if debugInstr { 399 log.Println("ReturnErr", outer) 400 } 401 fn := p.current.fn 402 if outer { 403 if !fn.isInline() { 404 panic("only support ReturnOuterErr in an inline call") 405 } 406 fn = fn.old.fn 407 } 408 results := fn.Type().(*types.Signature).Results() 409 n := results.Len() 410 if n > 0 { 411 last := results.At(n - 1) 412 if last.Type() == TyError { // last result is error 413 err := p.stk.Pop() 414 for i := 0; i < n-1; i++ { 415 p.doZeroLit(results.At(i).Type(), false) 416 } 417 p.stk.Push(err) 418 p.returnResults(n) 419 p.current.flows |= flowFlagReturn 420 return p 421 } 422 } 423 panic("TODO: last result type isn't an error") 424 } 425 426 func (p *CodeBuilder) returnResults(n int) { 427 var rets []ast.Expr 428 if n > 0 { 429 args := p.stk.GetArgs(n) 430 rets = make([]ast.Expr, n) 431 for i := 0; i < n; i++ { 432 rets[i] = args[i].Val 433 } 434 p.stk.PopN(n) 435 } 436 p.emitStmt(&ast.ReturnStmt{Results: rets}) 437 } 438 439 // Return func 440 func (p *CodeBuilder) Return(n int, src ...ast.Node) *CodeBuilder { 441 if debugInstr { 442 log.Println("Return", n) 443 } 444 fn := p.current.fn 445 results := fn.Type().(*types.Signature).Results() 446 checkFuncResults(p.pkg, p.stk.GetArgs(n), results, getSrc(src)) 447 if fn.isInline() { 448 for i := n - 1; i >= 0; i-- { 449 key := closureParamInst{fn, results.At(i)} 450 elem := p.stk.Pop() 451 p.doVarRef(p.paramInsts[key], nil, false) 452 p.stk.Push(elem) 453 p.doAssignWith(1, 1, nil) 454 } 455 p.Goto(p.getEndingLabel(fn)) 456 } else { 457 p.current.flows |= flowFlagReturn 458 p.returnResults(n) 459 } 460 return p 461 } 462 463 // Call func 464 func (p *CodeBuilder) Call(n int, ellipsis ...bool) *CodeBuilder { 465 var flags InstrFlags 466 if ellipsis != nil && ellipsis[0] { 467 flags = InstrFlagEllipsis 468 } 469 return p.CallWith(n, flags) 470 } 471 472 // CallWith always panics on error, while CallWithEx returns err if match function call failed. 473 func (p *CodeBuilder) CallWith(n int, flags InstrFlags, src ...ast.Node) *CodeBuilder { 474 if err := p.CallWithEx(n, flags, src...); err != nil { 475 panic(err) 476 } 477 return p 478 } 479 480 // CallWith always panics on error, while CallWithEx returns err if match function call failed. 481 // If an error ocurs, CallWithEx pops all function arguments from the CodeBuilder stack. 482 // In most case, you should call CallWith instead of CallWithEx. 483 func (p *CodeBuilder) CallWithEx(n int, flags InstrFlags, src ...ast.Node) error { 484 fn := p.stk.Get(-(n + 1)) 485 if t, ok := fn.Type.(*btiMethodType); ok { 486 n++ 487 fn.Type = t.Type 488 fn = p.stk.Get(-(n + 1)) 489 if t.eargs != nil { 490 for _, arg := range t.eargs { 491 p.Val(arg) 492 } 493 n += len(t.eargs) 494 } 495 } 496 args := p.stk.GetArgs(n) 497 if debugInstr { 498 log.Println("Call", n, int(flags), "//", fn.Type) 499 } 500 s := getSrc(src) 501 fn.Src = s 502 ret, err := matchFuncCall(p.pkg, fn, args, flags) 503 if err != nil { 504 p.stk.PopN(n) 505 return err 506 } 507 ret.Src = s 508 p.stk.Ret(n+1, ret) 509 return nil 510 } 511 512 type closureParamInst struct { 513 inst *Func 514 param *types.Var 515 } 516 517 type closureParamInsts struct { 518 paramInsts map[closureParamInst]*types.Var 519 } 520 521 func (p *closureParamInsts) init() { 522 p.paramInsts = make(map[closureParamInst]*types.Var) 523 } 524 525 func (p *CodeBuilder) getEndingLabel(fn *Func) *Label { 526 key := closureParamInst{fn, nil} 527 if v, ok := p.paramInsts[key]; ok { 528 return p.current.labels[v.Name()] 529 } 530 ending := p.pkg.autoName() 531 p.paramInsts[key] = types.NewParam(token.NoPos, nil, ending, nil) 532 return p.NewLabel(token.NoPos, ending) 533 } 534 535 func (p *CodeBuilder) needEndingLabel(fn *Func) (*Label, bool) { 536 key := closureParamInst{fn, nil} 537 if v, ok := p.paramInsts[key]; ok { 538 return p.current.labels[v.Name()], true 539 } 540 return nil, false 541 } 542 543 func (p *Func) inlineClosureEnd(cb *CodeBuilder) { 544 if ending, ok := cb.needEndingLabel(p); ok { 545 cb.Label(ending) 546 } 547 sig := p.Type().(*types.Signature) 548 cb.emitStmt(&ast.BlockStmt{List: cb.endFuncBody(p.old)}) 549 cb.stk.PopN(p.getInlineCallArity()) 550 results := sig.Results() 551 for i, n := 0, results.Len(); i < n; i++ { // return results & clean env 552 key := closureParamInst{p, results.At(i)} 553 cb.pushVal(cb.paramInsts[key], nil) 554 delete(cb.paramInsts, key) 555 } 556 for i, n := 0, getParamLen(sig); i < n; i++ { // clean env 557 key := closureParamInst{p, getParam(sig, i)} 558 delete(cb.paramInsts, key) 559 } 560 } 561 562 // CallInlineClosureStart func 563 func (p *CodeBuilder) CallInlineClosureStart(sig *types.Signature, arity int, ellipsis bool) *CodeBuilder { 564 if debugInstr { 565 log.Println("CallInlineClosureStart", arity, ellipsis) 566 } 567 pkg := p.pkg 568 closure := pkg.newInlineClosure(sig, arity) 569 results := sig.Results() 570 for i, n := 0, results.Len(); i < n; i++ { 571 p.emitVar(pkg, closure, results.At(i), false) 572 } 573 p.startFuncBody(closure, nil, &closure.old) 574 args := p.stk.GetArgs(arity) 575 var flags InstrFlags 576 if ellipsis { 577 flags = InstrFlagEllipsis 578 } 579 if err := matchFuncType(pkg, args, flags, sig, nil); err != nil { 580 panic(err) 581 } 582 n1 := getParamLen(sig) - 1 583 if sig.Variadic() && !ellipsis { 584 p.SliceLit(getParam(sig, n1).Type().(*types.Slice), arity-n1) 585 } 586 for i := n1; i >= 0; i-- { 587 p.emitVar(pkg, closure, getParam(sig, i), true) 588 } 589 return p 590 } 591 592 func (p *CodeBuilder) emitVar(pkg *Package, closure *Func, param *types.Var, withInit bool) { 593 name := pkg.autoName() 594 if withInit { 595 p.NewVarStart(param.Type(), name).EndInit(1) 596 } else { 597 p.NewVar(param.Type(), name) 598 } 599 key := closureParamInst{closure, param} 600 p.paramInsts[key] = p.current.scope.Lookup(name).(*types.Var) 601 } 602 603 // NewClosure func 604 func (p *CodeBuilder) NewClosure(params, results *Tuple, variadic bool) *Func { 605 sig := types.NewSignatureType(nil, nil, nil, params, results, variadic) 606 return p.NewClosureWith(sig) 607 } 608 609 // NewClosureWith func 610 func (p *CodeBuilder) NewClosureWith(sig *types.Signature) *Func { 611 if debugInstr { 612 t := sig.Params() 613 for i, n := 0, t.Len(); i < n; i++ { 614 v := t.At(i) 615 if _, ok := v.Type().(*unboundType); ok { 616 panic("can't use unbound type in func parameters") 617 } 618 } 619 } 620 return p.pkg.newClosure(sig) 621 } 622 623 // NewType func 624 func (p *CodeBuilder) NewType(name string, src ...ast.Node) *TypeDecl { 625 return p.NewTypeDefs().NewType(name, src...) 626 } 627 628 // AliasType func 629 func (p *CodeBuilder) AliasType(name string, typ types.Type, src ...ast.Node) *types.Named { 630 decl := p.NewTypeDefs().AliasType(name, typ, src...) 631 return decl.typ 632 } 633 634 // NewConstStart func 635 func (p *CodeBuilder) NewConstStart(typ types.Type, names ...string) *CodeBuilder { 636 if debugInstr { 637 log.Println("NewConstStart", names) 638 } 639 defs := p.valueDefs(token.CONST) 640 return p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.CONST, typ, names...).InitStart(p.pkg) 641 } 642 643 // NewVar func 644 func (p *CodeBuilder) NewVar(typ types.Type, names ...string) *CodeBuilder { 645 if debugInstr { 646 log.Println("NewVar", names) 647 } 648 defs := p.valueDefs(token.VAR) 649 p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.VAR, typ, names...) 650 return p 651 } 652 653 // NewVarStart func 654 func (p *CodeBuilder) NewVarStart(typ types.Type, names ...string) *CodeBuilder { 655 if debugInstr { 656 log.Println("NewVarStart", names) 657 } 658 defs := p.valueDefs(token.VAR) 659 return p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.VAR, typ, names...).InitStart(p.pkg) 660 } 661 662 // DefineVarStart func 663 func (p *CodeBuilder) DefineVarStart(pos token.Pos, names ...string) *CodeBuilder { 664 if debugInstr { 665 log.Println("DefineVarStart", names) 666 } 667 return p.pkg.newValueDecl( 668 ValueAt{}, p.current.scope, pos, token.DEFINE, nil, names...).InitStart(p.pkg) 669 } 670 671 // NewAutoVar func 672 func (p *CodeBuilder) NewAutoVar(pos token.Pos, name string, pv **types.Var) *CodeBuilder { 673 spec := &ast.ValueSpec{Names: []*ast.Ident{ident(name)}} 674 decl := &ast.GenDecl{Tok: token.VAR, Specs: []ast.Spec{spec}} 675 stmt := &ast.DeclStmt{ 676 Decl: decl, 677 } 678 if debugInstr { 679 log.Println("NewAutoVar", name) 680 } 681 p.emitStmt(stmt) 682 typ := &unboundType{ptypes: []*ast.Expr{&spec.Type}} 683 *pv = types.NewVar(pos, p.pkg.Types, name, typ) 684 if old := p.current.scope.Insert(*pv); old != nil { 685 oldPos := p.fset.Position(old.Pos()) 686 p.panicCodeErrorf( 687 pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldPos) 688 } 689 return p 690 } 691 692 // VarRef func: p.VarRef(nil) means underscore (_) 693 func (p *CodeBuilder) VarRef(ref interface{}, src ...ast.Node) *CodeBuilder { 694 return p.doVarRef(ref, getSrc(src), true) 695 } 696 697 func (p *CodeBuilder) doVarRef(ref interface{}, src ast.Node, allowDebug bool) *CodeBuilder { 698 if ref == nil { 699 if allowDebug && debugInstr { 700 log.Println("VarRef _") 701 } 702 p.stk.Push(&internal.Elem{ 703 Val: underscore, // _ 704 }) 705 } else { 706 switch v := ref.(type) { 707 case *types.Var: 708 if allowDebug && debugInstr { 709 log.Println("VarRef", v.Name(), v.Type()) 710 } 711 fn := p.current.fn 712 if fn != nil && fn.isInline() { // is in an inline call 713 key := closureParamInst{fn, v} 714 if arg, ok := p.paramInsts[key]; ok { // replace param with arg 715 v = arg 716 } 717 } 718 p.stk.Push(&internal.Elem{ 719 Val: toObjectExpr(p.pkg, v), Type: &refType{typ: v.Type()}, Src: src, 720 }) 721 default: 722 code, pos := p.loadExpr(src) 723 p.panicCodeErrorf(pos, "%s is not a variable", code) 724 } 725 } 726 return p 727 } 728 729 var ( 730 elemNone = &internal.Elem{} 731 ) 732 733 // None func 734 func (p *CodeBuilder) None() *CodeBuilder { 735 if debugInstr { 736 log.Println("None") 737 } 738 p.stk.Push(elemNone) 739 return p 740 } 741 742 // ZeroLit func 743 func (p *CodeBuilder) ZeroLit(typ types.Type) *CodeBuilder { 744 return p.doZeroLit(typ, true) 745 } 746 747 func (p *CodeBuilder) doZeroLit(typ types.Type, allowDebug bool) *CodeBuilder { 748 typ0 := typ 749 if allowDebug && debugInstr { 750 log.Println("ZeroLit //", typ) 751 } 752 retry: 753 switch t := typ.(type) { 754 case *types.Basic: 755 switch kind := t.Kind(); kind { 756 case types.Bool: 757 return p.Val(false) 758 case types.String: 759 return p.Val("") 760 case types.UnsafePointer: 761 return p.Val(nil) 762 default: 763 return p.Val(0) 764 } 765 case *types.Interface, *types.Map, *types.Slice, *types.Pointer, *types.Signature, *types.Chan: 766 return p.Val(nil) 767 case *types.Named: 768 typ = p.getUnderlying(t) 769 goto retry 770 } 771 ret := &ast.CompositeLit{} 772 switch t := typ.(type) { 773 case *unboundType: 774 if t.tBound == nil { 775 t.ptypes = append(t.ptypes, &ret.Type) 776 } else { 777 typ = t.tBound 778 typ0 = typ 779 ret.Type = toType(p.pkg, typ) 780 } 781 default: 782 ret.Type = toType(p.pkg, typ) 783 } 784 p.stk.Push(&internal.Elem{Type: typ0, Val: ret}) 785 return p 786 } 787 788 // MapLit func 789 func (p *CodeBuilder) MapLit(typ types.Type, arity int, src ...ast.Node) *CodeBuilder { 790 if err := p.MapLitEx(typ, arity, src...); err != nil { 791 panic(err) 792 } 793 return p 794 } 795 796 // MapLit func 797 func (p *CodeBuilder) MapLitEx(typ types.Type, arity int, src ...ast.Node) error { 798 if debugInstr { 799 log.Println("MapLit", typ, arity) 800 } 801 var t *types.Map 802 var typExpr ast.Expr 803 var pkg = p.pkg 804 if typ != nil { 805 var ok bool 806 switch tt := typ.(type) { 807 case *types.Named: 808 typExpr = toNamedType(pkg, tt) 809 t, ok = p.getUnderlying(tt).(*types.Map) 810 case *types.Map: 811 typExpr = toMapType(pkg, tt) 812 t, ok = tt, true 813 } 814 if !ok { 815 return p.newCodeErrorf(getPos(src), "type %v isn't a map", typ) 816 } 817 } 818 if arity == 0 { 819 if t == nil { 820 t = types.NewMap(types.Typ[types.String], TyEmptyInterface) 821 typ = t 822 typExpr = toMapType(pkg, t) 823 } 824 ret := &ast.CompositeLit{Type: typExpr} 825 p.stk.Push(&internal.Elem{Type: typ, Val: ret, Src: getSrc(src)}) 826 return nil 827 } 828 if (arity & 1) != 0 { 829 return p.newCodeErrorf(getPos(src), "MapLit: invalid arity, can't be odd - %d", arity) 830 } 831 var key, val types.Type 832 var args = p.stk.GetArgs(arity) 833 var check = (t != nil) 834 if check { 835 key, val = t.Key(), t.Elem() 836 } else { 837 key = boundElementType(pkg, args, 0, arity, 2) 838 val = boundElementType(pkg, args, 1, arity, 2) 839 t = types.NewMap(Default(pkg, key), Default(pkg, val)) 840 typ = t 841 typExpr = toMapType(pkg, t) 842 } 843 elts := make([]ast.Expr, arity>>1) 844 for i := 0; i < arity; i += 2 { 845 elts[i>>1] = &ast.KeyValueExpr{Key: args[i].Val, Value: args[i+1].Val} 846 if check { 847 if !AssignableTo(pkg, args[i].Type, key) { 848 src, pos := p.loadExpr(args[i].Src) 849 return p.newCodeErrorf( 850 pos, "cannot use %s (type %v) as type %v in map key", src, args[i].Type, key) 851 } else if !AssignableTo(pkg, args[i+1].Type, val) { 852 src, pos := p.loadExpr(args[i+1].Src) 853 return p.newCodeErrorf( 854 pos, "cannot use %s (type %v) as type %v in map value", src, args[i+1].Type, val) 855 } 856 } 857 } 858 p.stk.Ret(arity, &internal.Elem{ 859 Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src), 860 }) 861 return nil 862 } 863 864 func (p *CodeBuilder) toBoundArrayLen(elts []*internal.Elem, arity, limit int) int { 865 n := -1 866 max := -1 867 for i := 0; i < arity; i += 2 { 868 if elts[i].Val != nil { 869 n = p.toIntVal(elts[i], "index which must be non-negative integer constant") 870 } else { 871 n++ 872 } 873 if limit >= 0 && n >= limit { // error message 874 if elts[i].Src == nil { 875 pos := getSrcPos(elts[i+1].Src) 876 p.panicCodeErrorf(pos, "array index %d out of bounds [0:%d]", n, limit) 877 } 878 src, pos := p.loadExpr(elts[i].Src) 879 p.panicCodeErrorf(pos, "array index %s (value %d) out of bounds [0:%d]", src, n, limit) 880 } 881 if max < n { 882 max = n 883 } 884 } 885 return max + 1 886 } 887 888 func (p *CodeBuilder) toIntVal(v *internal.Elem, msg string) int { 889 if cval := v.CVal; cval != nil && cval.Kind() == constant.Int { 890 if v, ok := constant.Int64Val(cval); ok { 891 return int(v) 892 } 893 } 894 code, pos := p.loadExpr(v.Src) 895 p.panicCodeErrorf(pos, "cannot use %s as %s", code, msg) 896 return 0 897 } 898 899 func (p *CodeBuilder) indexElemExpr(args []*internal.Elem, i int) ast.Expr { 900 key := args[i].Val 901 if key == nil { // none 902 return args[i+1].Val 903 } 904 p.toIntVal(args[i], "index which must be non-negative integer constant") 905 return &ast.KeyValueExpr{Key: key, Value: args[i+1].Val} 906 } 907 908 // SliceLit func 909 func (p *CodeBuilder) SliceLit(typ types.Type, arity int, keyVal ...bool) *CodeBuilder { 910 var keyValMode = (keyVal != nil && keyVal[0]) 911 return p.SliceLitEx(typ, arity, keyValMode) 912 } 913 914 // SliceLitEx func 915 func (p *CodeBuilder) SliceLitEx(typ types.Type, arity int, keyVal bool, src ...ast.Node) *CodeBuilder { 916 var elts []ast.Expr 917 if debugInstr { 918 log.Println("SliceLit", typ, arity, keyVal) 919 } 920 var t *types.Slice 921 var typExpr ast.Expr 922 var pkg = p.pkg 923 if typ != nil { 924 switch tt := typ.(type) { 925 case *types.Named: 926 typExpr = toNamedType(pkg, tt) 927 t = p.getUnderlying(tt).(*types.Slice) 928 case *types.Slice: 929 typExpr = toSliceType(pkg, tt) 930 t = tt 931 default: 932 log.Panicln("SliceLit: typ isn't a slice type -", reflect.TypeOf(typ)) 933 } 934 } 935 if keyVal { // in keyVal mode 936 if (arity & 1) != 0 { 937 log.Panicln("SliceLit: invalid arity, can't be odd in keyVal mode -", arity) 938 } 939 args := p.stk.GetArgs(arity) 940 val := t.Elem() 941 n := arity >> 1 942 elts = make([]ast.Expr, n) 943 for i := 0; i < arity; i += 2 { 944 arg := args[i+1] 945 if !AssignableConv(pkg, arg.Type, val, arg) { 946 src, pos := p.loadExpr(args[i+1].Src) 947 p.panicCodeErrorf( 948 pos, "cannot use %s (type %v) as type %v in slice literal", src, args[i+1].Type, val) 949 } 950 elts[i>>1] = p.indexElemExpr(args, i) 951 } 952 } else { 953 if arity == 0 { 954 if t == nil { 955 t = types.NewSlice(TyEmptyInterface) 956 typ = t 957 typExpr = toSliceType(pkg, t) 958 } 959 p.stk.Push(&internal.Elem{ 960 Type: typ, Val: &ast.CompositeLit{Type: typExpr}, Src: getSrc(src), 961 }) 962 return p 963 } 964 var val types.Type 965 var args = p.stk.GetArgs(arity) 966 var check = (t != nil) 967 if check { 968 val = t.Elem() 969 } else { 970 val = boundElementType(pkg, args, 0, arity, 1) 971 t = types.NewSlice(Default(pkg, val)) 972 typ = t 973 typExpr = toSliceType(pkg, t) 974 } 975 elts = make([]ast.Expr, arity) 976 for i, arg := range args { 977 elts[i] = arg.Val 978 if check { 979 if !AssignableConv(pkg, arg.Type, val, arg) { 980 src, pos := p.loadExpr(arg.Src) 981 p.panicCodeErrorf( 982 pos, "cannot use %s (type %v) as type %v in slice literal", src, arg.Type, val) 983 } 984 } 985 } 986 } 987 p.stk.Ret(arity, &internal.Elem{ 988 Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src), 989 }) 990 return p 991 } 992 993 // ArrayLit func 994 func (p *CodeBuilder) ArrayLit(typ types.Type, arity int, keyVal ...bool) *CodeBuilder { 995 var keyValMode = (keyVal != nil && keyVal[0]) 996 return p.ArrayLitEx(typ, arity, keyValMode) 997 } 998 999 // ArrayLitEx func 1000 func (p *CodeBuilder) ArrayLitEx(typ types.Type, arity int, keyVal bool, src ...ast.Node) *CodeBuilder { 1001 var elts []ast.Expr 1002 if debugInstr { 1003 log.Println("ArrayLit", typ, arity, keyVal) 1004 } 1005 var t *types.Array 1006 var typExpr ast.Expr 1007 var pkg = p.pkg 1008 switch tt := typ.(type) { 1009 case *types.Named: 1010 typExpr = toNamedType(pkg, tt) 1011 t = p.getUnderlying(tt).(*types.Array) 1012 case *types.Array: 1013 typExpr = toArrayType(pkg, tt) 1014 t = tt 1015 default: 1016 log.Panicln("ArrayLit: typ isn't a array type -", reflect.TypeOf(typ)) 1017 } 1018 if keyVal { // in keyVal mode 1019 if (arity & 1) != 0 { 1020 log.Panicln("ArrayLit: invalid arity, can't be odd in keyVal mode -", arity) 1021 } 1022 n := int(t.Len()) 1023 args := p.stk.GetArgs(arity) 1024 max := p.toBoundArrayLen(args, arity, n) 1025 val := t.Elem() 1026 if n < 0 { 1027 t = types.NewArray(val, int64(max)) 1028 typ = t 1029 } 1030 elts = make([]ast.Expr, arity>>1) 1031 for i := 0; i < arity; i += 2 { 1032 if !AssignableTo(pkg, args[i+1].Type, val) { 1033 src, pos := p.loadExpr(args[i+1].Src) 1034 p.panicCodeErrorf( 1035 pos, "cannot use %s (type %v) as type %v in array literal", src, args[i+1].Type, val) 1036 } 1037 elts[i>>1] = p.indexElemExpr(args, i) 1038 } 1039 } else { 1040 args := p.stk.GetArgs(arity) 1041 val := t.Elem() 1042 if n := t.Len(); n < 0 { 1043 t = types.NewArray(val, int64(arity)) 1044 typ = t 1045 } else if int(n) < arity { 1046 pos := getSrcPos(args[n].Src) 1047 p.panicCodeErrorf(pos, "array index %d out of bounds [0:%d]", n, n) 1048 } 1049 elts = make([]ast.Expr, arity) 1050 for i, arg := range args { 1051 elts[i] = arg.Val 1052 if !AssignableConv(pkg, arg.Type, val, arg) { 1053 src, pos := p.loadExpr(arg.Src) 1054 p.panicCodeErrorf( 1055 pos, "cannot use %s (type %v) as type %v in array literal", src, arg.Type, val) 1056 } 1057 } 1058 } 1059 p.stk.Ret(arity, &internal.Elem{ 1060 Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src), 1061 }) 1062 return p 1063 } 1064 1065 // StructLit func 1066 func (p *CodeBuilder) StructLit(typ types.Type, arity int, keyVal bool, src ...ast.Node) *CodeBuilder { 1067 if debugInstr { 1068 log.Println("StructLit", typ, arity, keyVal) 1069 } 1070 var t *types.Struct 1071 var typExpr ast.Expr 1072 var pkg = p.pkg 1073 switch tt := typ.(type) { 1074 case *types.Named: 1075 typExpr = toNamedType(pkg, tt) 1076 t = p.getUnderlying(tt).(*types.Struct) 1077 case *types.Struct: 1078 typExpr = toStructType(pkg, tt) 1079 t = tt 1080 default: 1081 log.Panicln("StructLit: typ isn't a struct type -", reflect.TypeOf(typ)) 1082 } 1083 var elts []ast.Expr 1084 var n = t.NumFields() 1085 var args = p.stk.GetArgs(arity) 1086 if keyVal { 1087 if (arity & 1) != 0 { 1088 log.Panicln("StructLit: invalid arity, can't be odd in keyVal mode -", arity) 1089 } 1090 elts = make([]ast.Expr, arity>>1) 1091 for i := 0; i < arity; i += 2 { 1092 idx := p.toIntVal(args[i], "field which must be non-negative integer constant") 1093 if idx >= n { 1094 panic("invalid struct field index") 1095 } 1096 elt := t.Field(idx) 1097 eltTy, eltName := elt.Type(), elt.Name() 1098 if !AssignableTo(pkg, args[i+1].Type, eltTy) { 1099 src, pos := p.loadExpr(args[i+1].Src) 1100 p.panicCodeErrorf( 1101 pos, "cannot use %s (type %v) as type %v in value of field %s", 1102 src, args[i+1].Type, eltTy, eltName) 1103 } 1104 elts[i>>1] = &ast.KeyValueExpr{Key: ident(eltName), Value: args[i+1].Val} 1105 } 1106 } else if arity != n { 1107 if arity != 0 { 1108 fewOrMany := "few" 1109 if arity > n { 1110 fewOrMany = "many" 1111 } 1112 pos := getSrcPos(args[arity-1].Src) 1113 p.panicCodeErrorf(pos, "too %s values in %v{...}", fewOrMany, typ) 1114 } 1115 } else { 1116 elts = make([]ast.Expr, arity) 1117 for i, arg := range args { 1118 elts[i] = arg.Val 1119 eltTy := t.Field(i).Type() 1120 if !AssignableTo(pkg, arg.Type, eltTy) { 1121 src, pos := p.loadExpr(arg.Src) 1122 p.panicCodeErrorf( 1123 pos, "cannot use %s (type %v) as type %v in value of field %s", 1124 src, arg.Type, eltTy, t.Field(i).Name()) 1125 } 1126 } 1127 } 1128 p.stk.Ret(arity, &internal.Elem{ 1129 Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src), 1130 }) 1131 return p 1132 } 1133 1134 // Slice func 1135 func (p *CodeBuilder) Slice(slice3 bool, src ...ast.Node) *CodeBuilder { // a[i:j:k] 1136 if debugInstr { 1137 log.Println("Slice", slice3) 1138 } 1139 n := 3 1140 if slice3 { 1141 n++ 1142 } 1143 srcExpr := getSrc(src) 1144 args := p.stk.GetArgs(n) 1145 x := args[0] 1146 typ := x.Type 1147 switch t := typ.(type) { 1148 case *types.Slice: 1149 // nothing to do 1150 case *types.Basic: 1151 if t.Kind() == types.String || t.Kind() == types.UntypedString { 1152 if slice3 { 1153 code, pos := p.loadExpr(srcExpr) 1154 p.panicCodeErrorf(pos, "invalid operation %s (3-index slice of string)", code) 1155 } 1156 } else { 1157 code, pos := p.loadExpr(x.Src) 1158 p.panicCodeErrorf(pos, "cannot slice %s (type %v)", code, typ) 1159 } 1160 case *types.Array: 1161 typ = types.NewSlice(t.Elem()) 1162 case *types.Pointer: 1163 if tt, ok := t.Elem().(*types.Array); ok { 1164 typ = types.NewSlice(tt.Elem()) 1165 } else { 1166 code, pos := p.loadExpr(x.Src) 1167 p.panicCodeErrorf(pos, "cannot slice %s (type %v)", code, typ) 1168 } 1169 } 1170 var exprMax ast.Expr 1171 if slice3 { 1172 exprMax = args[3].Val 1173 } 1174 // TODO: check type 1175 elem := &internal.Elem{ 1176 Val: &ast.SliceExpr{ 1177 X: x.Val, Low: args[1].Val, High: args[2].Val, Max: exprMax, Slice3: slice3, 1178 }, 1179 Type: typ, Src: srcExpr, 1180 } 1181 p.stk.Ret(n, elem) 1182 return p 1183 } 1184 1185 // Index func: 1186 // - a[i] 1187 // - fn[T1, T2, ..., Tn] 1188 // - G[T1, T2, ..., Tn] 1189 func (p *CodeBuilder) Index(nidx int, twoValue bool, src ...ast.Node) *CodeBuilder { 1190 if debugInstr { 1191 log.Println("Index", nidx, twoValue) 1192 } 1193 args := p.stk.GetArgs(nidx + 1) 1194 if nidx > 0 { 1195 if _, ok := args[1].Type.(*TypeType); ok { 1196 return p.instantiate(nidx, args, src...) 1197 } 1198 } 1199 if nidx != 1 { 1200 panic("Index doesn't support a[i, j...] yet") 1201 } 1202 srcExpr := getSrc(src) 1203 typs, allowTwoValue := p.getIdxValTypes(args[0].Type, false, srcExpr) 1204 var tyRet types.Type 1205 if twoValue { // elem, ok = a[key] 1206 if !allowTwoValue { 1207 pos := getSrcPos(srcExpr) 1208 p.panicCodeError(pos, "assignment mismatch: 2 variables but 1 values") 1209 } 1210 pkg := p.pkg 1211 tyRet = types.NewTuple( 1212 pkg.NewParam(token.NoPos, "", typs[1]), 1213 pkg.NewParam(token.NoPos, "", types.Typ[types.Bool])) 1214 } else { // elem = a[key] 1215 tyRet = typs[1] 1216 } 1217 elem := &internal.Elem{ 1218 Val: &ast.IndexExpr{X: args[0].Val, Index: args[1].Val}, Type: tyRet, Src: srcExpr, 1219 } 1220 // TODO: check index type 1221 p.stk.Ret(2, elem) 1222 return p 1223 } 1224 1225 // IndexRef func 1226 func (p *CodeBuilder) IndexRef(nidx int, src ...ast.Node) *CodeBuilder { 1227 if debugInstr { 1228 log.Println("IndexRef", nidx) 1229 } 1230 if nidx != 1 { 1231 panic("IndexRef doesn't support a[i, j...] = val yet") 1232 } 1233 args := p.stk.GetArgs(2) 1234 typ := args[0].Type 1235 elemRef := &internal.Elem{ 1236 Val: &ast.IndexExpr{X: args[0].Val, Index: args[1].Val}, 1237 Src: getSrc(src), 1238 } 1239 if t, ok := typ.(*unboundType); ok { 1240 tyMapElem := &unboundMapElemType{key: args[1].Type, typ: t} 1241 elemRef.Type = &refType{typ: tyMapElem} 1242 } else { 1243 typs, _ := p.getIdxValTypes(typ, true, elemRef.Src) 1244 elemRef.Type = &refType{typ: typs[1]} 1245 // TODO: check index type 1246 } 1247 p.stk.Ret(2, elemRef) 1248 return p 1249 } 1250 1251 func (p *CodeBuilder) getIdxValTypes(typ types.Type, ref bool, idxSrc ast.Node) ([]types.Type, bool) { 1252 retry: 1253 switch t := typ.(type) { 1254 case *types.Slice: 1255 return []types.Type{tyInt, t.Elem()}, false 1256 case *types.Map: 1257 return []types.Type{t.Key(), t.Elem()}, true 1258 case *types.Array: 1259 return []types.Type{tyInt, t.Elem()}, false 1260 case *types.Pointer: 1261 elem := t.Elem() 1262 if named, ok := elem.(*types.Named); ok { 1263 elem = p.getUnderlying(named) 1264 } 1265 if e, ok := elem.(*types.Array); ok { 1266 return []types.Type{tyInt, e.Elem()}, false 1267 } 1268 case *types.Basic: 1269 if (t.Info() & types.IsString) != 0 { 1270 if ref { 1271 src, pos := p.loadExpr(idxSrc) 1272 p.panicCodeErrorf(pos, "cannot assign to %s (strings are immutable)", src) 1273 } 1274 return []types.Type{tyInt, TyByte}, false 1275 } 1276 case *types.Named: 1277 typ = p.getUnderlying(t) 1278 goto retry 1279 } 1280 src, pos := p.loadExpr(idxSrc) 1281 p.panicCodeErrorf(pos, "invalid operation: %s (type %v does not support indexing)", src, typ) 1282 return nil, false 1283 } 1284 1285 var ( 1286 tyInt = types.Typ[types.Int] 1287 ) 1288 1289 // Typ func 1290 func (p *CodeBuilder) Typ(typ types.Type, src ...ast.Node) *CodeBuilder { 1291 if debugInstr { 1292 log.Println("Typ", typ) 1293 } 1294 p.stk.Push(&internal.Elem{ 1295 Val: toType(p.pkg, typ), 1296 Type: NewTypeType(typ), 1297 Src: getSrc(src), 1298 }) 1299 return p 1300 } 1301 1302 // UntypedBigInt func 1303 func (p *CodeBuilder) UntypedBigInt(v *big.Int, src ...ast.Node) *CodeBuilder { 1304 pkg := p.pkg 1305 bigPkg := pkg.big() 1306 if v.IsInt64() { 1307 val := &ast.BasicLit{Kind: token.INT, Value: strconv.FormatInt(v.Int64(), 10)} 1308 p.Val(bigPkg.Ref("NewInt")).Val(val).Call(1) 1309 } else { 1310 /* 1311 func() *typ { 1312 v, _ := new(typ).SetString(strVal, 10) 1313 return v 1314 }() 1315 */ 1316 typ := bigPkg.Ref("Int").Type() 1317 retTyp := types.NewPointer(typ) 1318 ret := pkg.NewParam(token.NoPos, "", retTyp) 1319 p.NewClosure(nil, types.NewTuple(ret), false).BodyStart(pkg). 1320 DefineVarStart(token.NoPos, "v", "_"). 1321 Val(pkg.builtin.Ref("new")).Typ(typ).Call(1). 1322 MemberVal("SetString").Val(v.String()).Val(10).Call(2).EndInit(1). 1323 Val(p.Scope().Lookup("v")).Return(1). 1324 End().Call(0) 1325 } 1326 ret := p.stk.Get(-1) 1327 ret.Type, ret.CVal, ret.Src = pkg.utBigInt, constant.Make(v), getSrc(src) 1328 return p 1329 } 1330 1331 // UntypedBigRat func 1332 func (p *CodeBuilder) UntypedBigRat(v *big.Rat, src ...ast.Node) *CodeBuilder { 1333 pkg := p.pkg 1334 bigPkg := pkg.big() 1335 a, b := v.Num(), v.Denom() 1336 if a.IsInt64() && b.IsInt64() { 1337 va := &ast.BasicLit{Kind: token.INT, Value: strconv.FormatInt(a.Int64(), 10)} 1338 vb := &ast.BasicLit{Kind: token.INT, Value: strconv.FormatInt(b.Int64(), 10)} 1339 p.Val(bigPkg.Ref("NewRat")).Val(va).Val(vb).Call(2) 1340 } else { 1341 // new(big.Rat).SetFrac(a, b) 1342 p.Val(p.pkg.builtin.Ref("new")).Typ(bigPkg.Ref("Rat").Type()).Call(1). 1343 MemberVal("SetFrac").UntypedBigInt(a).UntypedBigInt(b).Call(2) 1344 } 1345 ret := p.stk.Get(-1) 1346 ret.Type, ret.CVal, ret.Src = pkg.utBigRat, constant.Make(v), getSrc(src) 1347 return p 1348 } 1349 1350 func (p *CodeBuilder) VarVal(name string, src ...ast.Node) *CodeBuilder { 1351 _, o := p.Scope().LookupParent(name, token.NoPos) 1352 if o == nil { 1353 log.Panicf("VarVal: variable `%v` not found\n", name) 1354 } 1355 return p.Val(o, src...) 1356 } 1357 1358 // Val func 1359 func (p *CodeBuilder) Val(v interface{}, src ...ast.Node) *CodeBuilder { 1360 if debugInstr { 1361 if o, ok := v.(types.Object); ok { 1362 log.Println("Val", o.Name(), o.Type()) 1363 } else { 1364 log.Println("Val", v, reflect.TypeOf(v)) 1365 } 1366 } 1367 fn := p.current.fn 1368 if fn != nil && fn.isInline() { // is in an inline call 1369 if param, ok := v.(*types.Var); ok { 1370 key := closureParamInst{fn, param} 1371 if arg, ok := p.paramInsts[key]; ok { // replace param with arg 1372 v = arg 1373 } 1374 } 1375 } 1376 return p.pushVal(v, getSrc(src)) 1377 } 1378 1379 func (p *CodeBuilder) pushVal(v interface{}, src ast.Node) *CodeBuilder { 1380 p.stk.Push(toExpr(p.pkg, v, src)) 1381 return p 1382 } 1383 1384 // Star func 1385 func (p *CodeBuilder) Star(src ...ast.Node) *CodeBuilder { 1386 if debugInstr { 1387 log.Println("Star") 1388 } 1389 arg := p.stk.Get(-1) 1390 ret := &internal.Elem{Val: &ast.StarExpr{X: arg.Val}, Src: getSrc(src)} 1391 argType := arg.Type 1392 retry: 1393 switch t := argType.(type) { 1394 case *TypeType: 1395 ret.Type = t.Pointer() 1396 case *types.Pointer: 1397 ret.Type = t.Elem() 1398 case *types.Named: 1399 argType = p.getUnderlying(t) 1400 goto retry 1401 default: 1402 code, pos := p.loadExpr(arg.Src) 1403 p.panicCodeErrorf(pos, "invalid indirect of %s (type %v)", code, t) 1404 } 1405 p.stk.Ret(1, ret) 1406 return p 1407 } 1408 1409 // Elem func 1410 func (p *CodeBuilder) Elem(src ...ast.Node) *CodeBuilder { 1411 if debugInstr { 1412 log.Println("Elem") 1413 } 1414 arg := p.stk.Get(-1) 1415 t, ok := arg.Type.(*types.Pointer) 1416 if !ok { 1417 code, pos := p.loadExpr(arg.Src) 1418 p.panicCodeErrorf(pos, "invalid indirect of %s (type %v)", code, arg.Type) 1419 } 1420 p.stk.Ret(1, &internal.Elem{Val: &ast.StarExpr{X: arg.Val}, Type: t.Elem(), Src: getSrc(src)}) 1421 return p 1422 } 1423 1424 // ElemRef func 1425 func (p *CodeBuilder) ElemRef(src ...ast.Node) *CodeBuilder { 1426 if debugInstr { 1427 log.Println("ElemRef") 1428 } 1429 arg := p.stk.Get(-1) 1430 t, ok := arg.Type.(*types.Pointer) 1431 if !ok { 1432 code, pos := p.loadExpr(arg.Src) 1433 p.panicCodeErrorf(pos, "invalid indirect of %s (type %v)", code, arg.Type) 1434 } 1435 p.stk.Ret(1, &internal.Elem{ 1436 Val: &ast.StarExpr{X: arg.Val}, Type: &refType{typ: t.Elem()}, Src: getSrc(src), 1437 }) 1438 return p 1439 } 1440 1441 // MemberVal func 1442 func (p *CodeBuilder) MemberVal(name string, src ...ast.Node) *CodeBuilder { 1443 _, err := p.Member(name, MemberFlagVal, src...) 1444 if err != nil { 1445 panic(err) 1446 } 1447 return p 1448 } 1449 1450 // MemberRef func 1451 func (p *CodeBuilder) MemberRef(name string, src ...ast.Node) *CodeBuilder { 1452 _, err := p.Member(name, MemberFlagRef, src...) 1453 if err != nil { 1454 panic(err) 1455 } 1456 return p 1457 } 1458 1459 func (p *CodeBuilder) refMember(typ types.Type, name string, argVal ast.Expr, src ast.Node) MemberKind { 1460 switch o := indirect(typ).(type) { 1461 case *types.Named: 1462 if struc, ok := p.getUnderlying(o).(*types.Struct); ok { 1463 name = p.getFieldName(o, name) 1464 if p.fieldRef(argVal, struc, name, src) { 1465 return MemberField 1466 } 1467 return p.refVField(o, name, argVal) 1468 } 1469 case *types.Struct: 1470 if p.fieldRef(argVal, o, name, src) { 1471 return MemberField 1472 } 1473 } 1474 return MemberInvalid 1475 } 1476 1477 func (p *CodeBuilder) fieldRef(x ast.Expr, o *types.Struct, name string, src ast.Node) bool { 1478 for i, n := 0, o.NumFields(); i < n; i++ { 1479 fld := o.Field(i) 1480 if fld.Name() == name { 1481 if p.rec != nil { 1482 p.rec.Member(src, fld) 1483 } 1484 p.stk.Ret(1, &internal.Elem{ 1485 Val: &ast.SelectorExpr{X: x, Sel: ident(name)}, 1486 Type: &refType{typ: fld.Type()}, 1487 }) 1488 return true 1489 } else if fld.Embedded() { 1490 fldt := fld.Type() 1491 if o, ok := fldt.(*types.Pointer); ok { 1492 fldt = o.Elem() 1493 } 1494 if t, ok := fldt.(*types.Named); ok { 1495 u := p.getUnderlying(t) 1496 if struc, ok := u.(*types.Struct); ok { 1497 if p.fieldRef(x, struc, name, src) || p.refVField(t, name, nil) != MemberInvalid { 1498 return true 1499 } 1500 } 1501 } 1502 } 1503 } 1504 return false 1505 } 1506 1507 type ( 1508 MemberKind int 1509 MemberFlag int 1510 ) 1511 1512 const ( 1513 MemberInvalid MemberKind = iota 1514 MemberMethod 1515 MemberAutoProperty 1516 MemberField 1517 memberBad MemberKind = -1 1518 ) 1519 1520 const ( 1521 MemberFlagVal MemberFlag = iota 1522 MemberFlagMethodAlias 1523 MemberFlagAutoProperty 1524 MemberFlagRef MemberFlag = -1 1525 1526 // private state 1527 memberFlagMethodToFunc MemberFlag = -2 1528 ) 1529 1530 func aliasNameOf(name string, flag MemberFlag) (string, MemberFlag) { 1531 // flag > 0: (flag == MemberFlagMethodAlias || flag == MemberFlagAutoProperty) 1532 if flag > 0 && name != "" { 1533 if c := name[0]; c >= 'a' && c <= 'z' { 1534 return string(rune(c)+('A'-'a')) + name[1:], flag 1535 } 1536 flag = MemberFlagVal 1537 } 1538 return "", flag 1539 } 1540 1541 // Member access member by its name. 1542 // src should point to the full source node `x.sel` 1543 func (p *CodeBuilder) Member(name string, flag MemberFlag, src ...ast.Node) (kind MemberKind, err error) { 1544 srcExpr := getSrc(src) 1545 arg := p.stk.Get(-1) 1546 if debugInstr { 1547 log.Println("Member", name, flag, "//", arg.Type) 1548 } 1549 switch arg.Type { 1550 case p.pkg.utBigInt, p.pkg.utBigRat, p.pkg.utBigFlt: 1551 arg.Type = DefaultConv(p.pkg, arg.Type, arg) 1552 } 1553 at := arg.Type 1554 if flag == MemberFlagRef { 1555 kind = p.refMember(at, name, arg.Val, srcExpr) 1556 } else { 1557 t, isType := at.(*TypeType) 1558 if isType { // (T).method or (*T).method 1559 at = t.Type() 1560 flag = memberFlagMethodToFunc 1561 } 1562 aliasName, flag := aliasNameOf(name, flag) 1563 kind = p.findMember(at, name, aliasName, flag, arg, srcExpr) 1564 if isType && kind != MemberMethod { 1565 code, pos := p.loadExpr(srcExpr) 1566 return MemberInvalid, p.newCodeError( 1567 pos, fmt.Sprintf("%s undefined (type %v has no method %s)", code, at, name)) 1568 } 1569 } 1570 if kind > 0 { 1571 return 1572 } 1573 code, pos := p.loadExpr(srcExpr) 1574 return MemberInvalid, p.newCodeError( 1575 pos, fmt.Sprintf("%s undefined (type %v has no field or method %s)", code, arg.Type, name)) 1576 } 1577 1578 func (p *CodeBuilder) getUnderlying(t *types.Named) types.Type { 1579 u := t.Underlying() 1580 if u == nil { 1581 p.loadNamed(p.pkg, t) 1582 u = t.Underlying() 1583 } 1584 return u 1585 } 1586 1587 func (p *CodeBuilder) ensureLoaded(typ types.Type) { 1588 if t, ok := typ.(*types.Pointer); ok { 1589 typ = t.Elem() 1590 } 1591 if t, ok := typ.(*types.Named); ok && (t.NumMethods() == 0 || t.Underlying() == nil) { 1592 if debugMatch { 1593 log.Println("==> EnsureLoaded", typ) 1594 } 1595 p.loadNamed(p.pkg, t) 1596 } 1597 } 1598 1599 func getUnderlying(pkg *Package, typ types.Type) types.Type { 1600 u := typ.Underlying() 1601 if u == nil { 1602 if t, ok := typ.(*types.Named); ok { 1603 pkg.cb.loadNamed(pkg, t) 1604 u = t.Underlying() 1605 } 1606 } 1607 return u 1608 } 1609 1610 func (p *CodeBuilder) findMember( 1611 typ types.Type, name, aliasName string, flag MemberFlag, arg *Element, srcExpr ast.Node) MemberKind { 1612 var named *types.Named 1613 retry: 1614 switch o := typ.(type) { 1615 case *types.Pointer: 1616 switch t := o.Elem().(type) { 1617 case *types.Named: 1618 u := p.getUnderlying(t) // may cause to loadNamed (delay-loaded) 1619 struc, fstruc := u.(*types.Struct) 1620 if fstruc { 1621 name = p.getFieldName(t, name) 1622 if kind := p.normalField(struc, name, arg, srcExpr); kind != MemberInvalid { 1623 return kind 1624 } 1625 } 1626 if kind := p.method(t, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid { 1627 return kind 1628 } 1629 if fstruc { 1630 if kind := p.findVField(t, name, arg, srcExpr); kind != MemberInvalid { 1631 return kind 1632 } 1633 return p.embeddedField(struc, name, aliasName, flag, arg, srcExpr) 1634 } 1635 case *types.Struct: 1636 if kind := p.field(t, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid { 1637 return kind 1638 } 1639 } 1640 case *types.Named: 1641 named, typ = o, p.getUnderlying(o) // may cause to loadNamed (delay-loaded) 1642 if kind := p.method(o, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid { 1643 return kind 1644 } 1645 if _, ok := typ.(*types.Struct); ok { 1646 name = p.getFieldName(o, name) 1647 } 1648 goto retry 1649 case *types.Struct: 1650 if kind := p.field(o, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid { 1651 return kind 1652 } 1653 if named != nil { 1654 return p.findVField(named, name, arg, srcExpr) 1655 } 1656 case *types.Interface: 1657 o.Complete() 1658 if kind := p.method(o, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid { 1659 return kind 1660 } 1661 case *types.Basic, *types.Slice, *types.Map, *types.Chan: 1662 return p.btiMethod(p.getBuiltinTI(o), name, aliasName, flag, srcExpr) 1663 } 1664 return MemberInvalid 1665 } 1666 1667 type methodList interface { 1668 NumMethods() int 1669 Method(i int) *types.Func 1670 } 1671 1672 func selector(arg *Element, name string) *ast.SelectorExpr { 1673 denoted := &ast.Object{Data: arg} 1674 return &ast.SelectorExpr{X: arg.Val, Sel: &ast.Ident{Name: name, Obj: denoted}} 1675 } 1676 1677 func denoteRecv(v *ast.SelectorExpr) *Element { 1678 if o := v.Sel.Obj; o != nil { 1679 if e, ok := o.Data.(*Element); ok { 1680 return e 1681 } 1682 } 1683 return nil 1684 } 1685 1686 func getDenoted(expr ast.Expr) *ast.Object { 1687 switch v := expr.(type) { 1688 case *ast.SelectorExpr: 1689 return v.Sel.Obj 1690 case *ast.Ident: 1691 return v.Obj 1692 default: 1693 return nil 1694 } 1695 } 1696 1697 func setDenoted(expr ast.Expr, denoted *ast.Object) { 1698 switch v := expr.(type) { 1699 case *ast.SelectorExpr: 1700 v.Sel.Obj = denoted 1701 case *ast.Ident: 1702 v.Obj = denoted 1703 } 1704 } 1705 1706 func (p *CodeBuilder) allowAccess(pkg *types.Package, name string) bool { 1707 if !ast.IsExported(name) && pkg != nil && pkg.Path() != p.pkg.Path() { 1708 return false 1709 } 1710 return true 1711 } 1712 1713 func (p *CodeBuilder) method( 1714 o methodList, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node) (kind MemberKind) { 1715 var found *types.Func 1716 var exact bool 1717 for i, n := 0, o.NumMethods(); i < n; i++ { 1718 method := o.Method(i) 1719 v := method.Name() 1720 if !p.allowAccess(method.Pkg(), v) { 1721 continue 1722 } 1723 if v == name { 1724 found, exact = method, true 1725 break 1726 } else if flag > 0 && v == aliasName { 1727 found = method 1728 if method.Pkg() != p.pkg.Types { 1729 break 1730 } 1731 } 1732 } 1733 if found != nil { 1734 autoprop := !exact && flag == MemberFlagAutoProperty 1735 typ := found.Type() 1736 if autoprop && !methodHasAutoProperty(typ, 0) { 1737 return memberBad 1738 } 1739 sel := selector(arg, found.Name()) 1740 p.stk.Ret(1, &internal.Elem{ 1741 Val: sel, 1742 Type: methodSigOf(typ, flag, arg, sel), 1743 Src: src, 1744 }) 1745 if p.rec != nil { 1746 p.rec.Member(src, found) 1747 } 1748 if autoprop { 1749 p.CallWith(0, 0, src) 1750 return MemberAutoProperty 1751 } 1752 return MemberMethod 1753 } 1754 if t, ok := o.(*types.Named); ok { 1755 kind = p.btiMethod(p.getBuiltinTI(t), name, aliasName, flag, src) 1756 } 1757 return 1758 } 1759 1760 func isTypeConvert(otyp, typ types.Type) (string, bool) { 1761 if otyp != typ { 1762 if t, ok := typ.Underlying().(*types.Basic); ok && 1763 (t.Info()&types.IsUntyped) == 0 { 1764 return t.Name(), true 1765 } 1766 } 1767 return "", false 1768 } 1769 1770 func (p *CodeBuilder) btiMethod( 1771 o *builtinTI, name, aliasName string, flag MemberFlag, src ast.Node) MemberKind { 1772 if o != nil { 1773 for i, n := 0, o.NumMethods(); i < n; i++ { 1774 method := o.Method(i) 1775 v := method.name 1776 if v == name || (flag > 0 && v == aliasName) { 1777 autoprop := flag == MemberFlagAutoProperty && v == aliasName 1778 this := p.stk.Pop() 1779 if fn, ok := isTypeConvert(o.typ, this.Type); ok { 1780 this.Val = &ast.CallExpr{ 1781 Fun: ast.NewIdent(fn), 1782 Args: []ast.Expr{this.Val}, 1783 } 1784 this.Type = &btiMethodType{Type: o.typ, eargs: method.eargs} 1785 } else { 1786 this.Type = &btiMethodType{Type: this.Type, eargs: method.eargs} 1787 } 1788 p.Val(method.fn, src) 1789 p.stk.Push(this) 1790 if p.rec != nil { 1791 p.rec.Member(src, method.fn) 1792 } 1793 if autoprop { 1794 p.CallWith(0, 0, src) 1795 return MemberAutoProperty 1796 } 1797 return MemberMethod 1798 } 1799 } 1800 } 1801 return MemberInvalid 1802 } 1803 1804 func (p *CodeBuilder) normalField( 1805 o *types.Struct, name string, arg *Element, src ast.Node) MemberKind { 1806 for i, n := 0, o.NumFields(); i < n; i++ { 1807 fld := o.Field(i) 1808 v := fld.Name() 1809 if !p.allowAccess(fld.Pkg(), v) { 1810 continue 1811 } 1812 if v == name { 1813 p.stk.Ret(1, &internal.Elem{ 1814 Val: selector(arg, name), 1815 Type: fld.Type(), 1816 Src: src, 1817 }) 1818 if p.rec != nil { 1819 p.rec.Member(src, fld) 1820 } 1821 return MemberField 1822 } 1823 } 1824 return MemberInvalid 1825 } 1826 1827 func (p *CodeBuilder) embeddedField( 1828 o *types.Struct, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node) MemberKind { 1829 for i, n := 0, o.NumFields(); i < n; i++ { 1830 if fld := o.Field(i); fld.Embedded() { 1831 if kind := p.findMember(fld.Type(), name, aliasName, flag, arg, src); kind != MemberInvalid { 1832 return kind 1833 } 1834 } 1835 } 1836 return MemberInvalid 1837 } 1838 1839 func (p *CodeBuilder) field( 1840 o *types.Struct, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node) MemberKind { 1841 if kind := p.normalField(o, name, arg, src); kind != MemberInvalid { 1842 return kind 1843 } 1844 return p.embeddedField(o, name, aliasName, flag, arg, src) 1845 } 1846 1847 func toFuncSig(sig *types.Signature, recv *types.Var) *types.Signature { 1848 sp := sig.Params() 1849 spLen := sp.Len() 1850 vars := make([]*types.Var, spLen+1) 1851 vars[0] = recv 1852 for i := 0; i < spLen; i++ { 1853 vars[i+1] = sp.At(i) 1854 } 1855 return types.NewSignatureType(nil, nil, nil, types.NewTuple(vars...), sig.Results(), sig.Variadic()) 1856 } 1857 1858 func methodToFuncSig(pkg *Package, o types.Object, fn *Element) *types.Signature { 1859 sig := o.Type().(*types.Signature) 1860 recv := sig.Recv() 1861 if recv == nil { 1862 fn.Val = toObjectExpr(pkg, o) 1863 return sig 1864 } 1865 1866 sel := fn.Val.(*ast.SelectorExpr) 1867 sel.Sel = ident(o.Name()) 1868 sel.X = &ast.ParenExpr{X: sel.X} 1869 return toFuncSig(sig, recv) 1870 } 1871 1872 func methodSigOf(typ types.Type, flag MemberFlag, arg *Element, sel *ast.SelectorExpr) types.Type { 1873 if flag != memberFlagMethodToFunc { 1874 return methodCallSig(typ) 1875 } 1876 1877 sig := typ.(*types.Signature) 1878 if _, ok := CheckFuncEx(sig); ok { 1879 return typ 1880 } 1881 1882 at := arg.Type.(*TypeType).typ 1883 recv := sig.Recv().Type() 1884 _, isPtr := recv.(*types.Pointer) // recv is a pointer 1885 if t, ok := at.(*types.Pointer); ok { 1886 if !isPtr { 1887 if _, ok := recv.Underlying().(*types.Interface); !ok { // and recv isn't a interface 1888 log.Panicf("recv of method %v.%s isn't a pointer\n", t.Elem(), sel.Sel.Name) 1889 } 1890 } 1891 } else if isPtr { // use *T 1892 at = types.NewPointer(at) 1893 sel.X = &ast.StarExpr{X: sel.X} 1894 } 1895 sel.X = &ast.ParenExpr{X: sel.X} 1896 1897 return toFuncSig(sig, types.NewVar(token.NoPos, nil, "", at)) 1898 } 1899 1900 func methodCallSig(typ types.Type) types.Type { 1901 sig := typ.(*types.Signature) 1902 if _, ok := CheckFuncEx(sig); ok { 1903 return typ 1904 } 1905 return types.NewSignatureType(nil, nil, nil, sig.Params(), sig.Results(), sig.Variadic()) 1906 } 1907 1908 func indirect(typ types.Type) types.Type { 1909 if t, ok := typ.(*types.Pointer); ok { 1910 typ = t.Elem() 1911 } 1912 return typ 1913 } 1914 1915 // IncDec func 1916 func (p *CodeBuilder) IncDec(op token.Token, src ...ast.Node) *CodeBuilder { 1917 name := goxPrefix + incdecOps[op] 1918 if debugInstr { 1919 log.Println("IncDec", op) 1920 } 1921 pkg := p.pkg 1922 arg := p.stk.Pop() 1923 if t, ok := arg.Type.(*refType).typ.(*types.Named); ok { 1924 op := lookupMethod(t, name) 1925 if op != nil { 1926 fn := &internal.Elem{ 1927 Val: &ast.SelectorExpr{X: arg.Val, Sel: ident(name)}, 1928 Type: realType(op.Type()), 1929 } 1930 ret := toFuncCall(pkg, fn, []*Element{arg}, 0) 1931 if ret.Type != nil { 1932 p.shouldNoResults(name, src) 1933 } 1934 p.emitStmt(&ast.ExprStmt{X: ret.Val}) 1935 return p 1936 } 1937 } 1938 fn := pkg.builtin.Ref(name) 1939 t := fn.Type().(*TyInstruction) 1940 if _, err := t.instr.Call(pkg, []*Element{arg}, 0, nil); err != nil { 1941 panic(err) 1942 } 1943 return p 1944 } 1945 1946 var ( 1947 incdecOps = [...]string{ 1948 token.INC: "Inc", 1949 token.DEC: "Dec", 1950 } 1951 ) 1952 1953 // AssignOp func 1954 func (p *CodeBuilder) AssignOp(op token.Token, src ...ast.Node) *CodeBuilder { 1955 args := p.stk.GetArgs(2) 1956 stmt := callAssignOp(p.pkg, op, args, src) 1957 p.emitStmt(stmt) 1958 p.stk.PopN(2) 1959 return p 1960 } 1961 1962 func checkDivisionByZero(cb *CodeBuilder, a, b *internal.Elem) { 1963 if a.CVal == nil { 1964 if isNormalInt(cb, a) { 1965 if c := b.CVal; c != nil { 1966 switch c.Kind() { 1967 case constant.Int, constant.Float, constant.Complex: 1968 if constant.Sign(c) == 0 { 1969 pos := getSrcPos(b.Src) 1970 cb.panicCodeError(pos, "invalid operation: division by zero") 1971 } 1972 } 1973 } 1974 } 1975 } else if c := b.CVal; c != nil { 1976 switch c.Kind() { 1977 case constant.Int, constant.Float, constant.Complex: 1978 if constant.Sign(c) == 0 { 1979 pos := getSrcPos(b.Src) 1980 cb.panicCodeError(pos, "invalid operation: division by zero") 1981 } 1982 } 1983 } 1984 } 1985 1986 func callAssignOp(pkg *Package, tok token.Token, args []*internal.Elem, src []ast.Node) ast.Stmt { 1987 name := goxPrefix + assignOps[tok] 1988 if debugInstr { 1989 log.Println("AssignOp", tok, name) 1990 } 1991 if t, ok := args[0].Type.(*refType).typ.(*types.Named); ok { 1992 op := lookupMethod(t, name) 1993 if op != nil { 1994 fn := &internal.Elem{ 1995 Val: &ast.SelectorExpr{X: args[0].Val, Sel: ident(name)}, 1996 Type: realType(op.Type()), 1997 } 1998 ret := toFuncCall(pkg, fn, args, 0) 1999 if ret.Type != nil { 2000 pkg.cb.shouldNoResults(name, src) 2001 } 2002 return &ast.ExprStmt{X: ret.Val} 2003 } 2004 } 2005 op := pkg.builtin.Ref(name) 2006 if tok == token.QUO_ASSIGN { 2007 checkDivisionByZero(&pkg.cb, &internal.Elem{Val: args[0].Val, Type: args[0].Type.(*refType).typ}, args[1]) 2008 } 2009 fn := &internal.Elem{ 2010 Val: ident(op.Name()), Type: op.Type(), 2011 } 2012 toFuncCall(pkg, fn, args, 0) 2013 return &ast.AssignStmt{ 2014 Tok: tok, 2015 Lhs: []ast.Expr{args[0].Val}, 2016 Rhs: []ast.Expr{args[1].Val}, 2017 } 2018 } 2019 2020 func (p *CodeBuilder) shouldNoResults(name string, src []ast.Node) { 2021 pos := token.NoPos 2022 if src != nil { 2023 pos = src[0].Pos() 2024 } 2025 p.panicCodeErrorf(pos, "operator %s should return no results\n", name) 2026 } 2027 2028 var ( 2029 assignOps = [...]string{ 2030 token.ADD_ASSIGN: "AddAssign", // += 2031 token.SUB_ASSIGN: "SubAssign", // -= 2032 token.MUL_ASSIGN: "MulAssign", // *= 2033 token.QUO_ASSIGN: "QuoAssign", // /= 2034 token.REM_ASSIGN: "RemAssign", // %= 2035 2036 token.AND_ASSIGN: "AndAssign", // &= 2037 token.OR_ASSIGN: "OrAssign", // |= 2038 token.XOR_ASSIGN: "XorAssign", // ^= 2039 token.AND_NOT_ASSIGN: "AndNotAssign", // &^= 2040 token.SHL_ASSIGN: "LshAssign", // <<= 2041 token.SHR_ASSIGN: "RshAssign", // >>= 2042 } 2043 ) 2044 2045 // Assign func 2046 func (p *CodeBuilder) Assign(lhs int, rhs ...int) *CodeBuilder { 2047 var v int 2048 if rhs != nil { 2049 v = rhs[0] 2050 } else { 2051 v = lhs 2052 } 2053 if debugInstr { 2054 log.Println("Assign", lhs, v) 2055 } 2056 return p.doAssignWith(lhs, v, nil) 2057 } 2058 2059 // AssignWith func 2060 func (p *CodeBuilder) AssignWith(lhs, rhs int, src ...ast.Node) *CodeBuilder { 2061 if debugInstr { 2062 log.Println("Assign", lhs, rhs) 2063 } 2064 return p.doAssignWith(lhs, rhs, getSrc(src)) 2065 } 2066 2067 func (p *CodeBuilder) doAssignWith(lhs, rhs int, src ast.Node) *CodeBuilder { 2068 mkBlockStmt := false 2069 args := p.stk.GetArgs(lhs + rhs) 2070 stmt := &ast.AssignStmt{ 2071 Tok: token.ASSIGN, 2072 Lhs: make([]ast.Expr, lhs), 2073 Rhs: make([]ast.Expr, rhs), 2074 } 2075 if rhs == 1 { 2076 if rhsVals, ok := args[lhs].Type.(*types.Tuple); ok { 2077 if lhs != rhsVals.Len() { 2078 pos := getSrcPos(src) 2079 caller := getCaller(args[lhs]) 2080 p.panicCodeErrorf( 2081 pos, "assignment mismatch: %d variables but %v returns %d values", 2082 lhs, caller, rhsVals.Len()) 2083 } 2084 for i := 0; i < lhs; i++ { 2085 val := &internal.Elem{Type: rhsVals.At(i).Type()} 2086 checkAssignType(p.pkg, args[i].Type, val) 2087 stmt.Lhs[i] = args[i].Val 2088 } 2089 stmt.Rhs[0] = args[lhs].Val 2090 goto done 2091 } 2092 } 2093 if lhs == rhs { 2094 mkBlockStmt = hasBfRefType(args) 2095 if mkBlockStmt { // { 2096 args = copyArgs(args) 2097 p.stk.PopN(lhs << 1) 2098 p.Block() 2099 } 2100 for i := 0; i < lhs; i++ { 2101 lhsType := args[i].Type 2102 bfr, bfAssign := lhsType.(*bfRefType) 2103 if bfAssign { 2104 lhsType = &refType{typ: bfr.typ} 2105 } 2106 checkAssignType(p.pkg, lhsType, args[lhs+i]) 2107 stmt.Lhs[i] = args[i].Val 2108 stmt.Rhs[i] = args[lhs+i].Val 2109 if bfAssign { 2110 bfr.assign(p, &stmt.Lhs[i], &stmt.Rhs[i]) 2111 } 2112 } 2113 } else { 2114 pos := getSrcPos(src) 2115 p.panicCodeErrorf( 2116 pos, "assignment mismatch: %d variables but %d values", lhs, rhs) 2117 } 2118 done: 2119 p.emitStmt(stmt) 2120 if mkBlockStmt { // } 2121 p.End() 2122 } else { 2123 p.stk.PopN(lhs + rhs) 2124 } 2125 return p 2126 } 2127 2128 func hasBfRefType(args []*internal.Elem) bool { 2129 for _, arg := range args { 2130 if _, ok := arg.Type.(*bfRefType); ok { 2131 return true 2132 } 2133 } 2134 return false 2135 } 2136 2137 func lookupMethod(t *types.Named, name string) types.Object { 2138 for i, n := 0, t.NumMethods(); i < n; i++ { 2139 m := t.Method(i) 2140 if m.Name() == name { 2141 return m 2142 } 2143 } 2144 return nil 2145 } 2146 2147 func doUnaryOp(cb *CodeBuilder, op token.Token, args []*internal.Elem, flags InstrFlags) (ret *internal.Elem, err error) { 2148 name := goxPrefix + unaryOps[op] 2149 pkg := cb.pkg 2150 typ := args[0].Type 2151 retry: 2152 switch t := typ.(type) { 2153 case *types.Named: 2154 lm := lookupMethod(t, name) 2155 if lm != nil { 2156 fn := &internal.Elem{ 2157 Val: &ast.SelectorExpr{X: args[0].Val, Sel: ident(name)}, 2158 Type: realType(lm.Type()), 2159 } 2160 return matchFuncCall(pkg, fn, args, flags|instrFlagOpFunc) 2161 } 2162 case *types.Pointer: 2163 typ = t.Elem() 2164 goto retry 2165 } 2166 lm := pkg.builtin.Ref(name) 2167 return matchFuncCall(pkg, toObject(pkg, lm, nil), args, flags) 2168 } 2169 2170 // UnaryOp: 2171 // - cb.UnaryOp(op token.Token) 2172 // - cb.UnaryOp(op token.Token, twoValue bool) 2173 // - cb.UnaryOp(op token.Token, twoValue bool, src ast.Node) 2174 func (p *CodeBuilder) UnaryOp(op token.Token, params ...interface{}) *CodeBuilder { 2175 var src ast.Node 2176 var flags InstrFlags 2177 switch len(params) { 2178 case 2: 2179 src, _ = params[1].(ast.Node) 2180 fallthrough 2181 case 1: 2182 if params[0].(bool) { 2183 flags = InstrFlagTwoValue 2184 } 2185 } 2186 if debugInstr { 2187 log.Println("UnaryOp", op, "flags:", flags) 2188 } 2189 ret, err := doUnaryOp(p, op, p.stk.GetArgs(1), flags) 2190 if err != nil { 2191 panic(err) 2192 } 2193 ret.Src = src 2194 p.stk.Ret(1, ret) 2195 return p 2196 } 2197 2198 // BinaryOp func 2199 func (p *CodeBuilder) BinaryOp(op token.Token, src ...ast.Node) *CodeBuilder { 2200 const ( 2201 errNotFound = syscall.ENOENT 2202 ) 2203 if debugInstr { 2204 log.Println("BinaryOp", xtoken.String(op)) 2205 } 2206 pkg := p.pkg 2207 name := goxPrefix + binaryOps[op] 2208 args := p.stk.GetArgs(2) 2209 2210 var ret *internal.Elem 2211 var err error = errNotFound 2212 isUserDef := false 2213 arg0 := args[0].Type 2214 named0, ok0 := checkNamed(arg0) 2215 if ok0 { 2216 if fn, e := pkg.MethodToFunc(arg0, name, src...); e == nil { 2217 ret, err = matchFuncCall(pkg, fn, args, instrFlagBinaryOp) 2218 isUserDef = true 2219 } 2220 } 2221 if err != nil { 2222 arg1 := args[1].Type 2223 if named1, ok1 := checkNamed(arg1); ok1 && named0 != named1 { 2224 if fn, e := pkg.MethodToFunc(arg1, name, src...); e == nil { 2225 ret, err = matchFuncCall(pkg, fn, args, instrFlagBinaryOp) 2226 isUserDef = true 2227 } 2228 } 2229 } 2230 if err != nil && !isUserDef { 2231 if op == token.QUO { 2232 checkDivisionByZero(p, args[0], args[1]) 2233 } 2234 if op == token.EQL || op == token.NEQ { 2235 if !ComparableTo(pkg, args[0], args[1]) { 2236 err = errors.New("mismatched types") 2237 } else { 2238 ret, err = &internal.Elem{ 2239 Val: &ast.BinaryExpr{ 2240 X: checkParenExpr(args[0].Val), Op: op, 2241 Y: checkParenExpr(args[1].Val), 2242 }, 2243 Type: types.Typ[types.UntypedBool], 2244 CVal: binaryOp(p, op, args), 2245 }, nil 2246 } 2247 } else if lm := pkg.builtin.TryRef(name); lm != nil { 2248 ret, err = matchFuncCall(pkg, toObject(pkg, lm, nil), args, 0) 2249 } else { 2250 err = errNotFound 2251 } 2252 } 2253 2254 expr := getSrc(src) 2255 if err != nil { 2256 opstr := xtoken.String(op) 2257 src, pos := p.loadExpr(expr) 2258 if src == "" { 2259 src = opstr 2260 } 2261 if err != errNotFound { 2262 p.panicCodeErrorf( 2263 pos, "invalid operation: %s (mismatched types %v and %v)", src, arg0, args[1].Type) 2264 } else { 2265 arg0Src, _ := p.loadExpr(args[0].Src) 2266 p.panicCodeErrorf( 2267 pos, "invalid operation: operator %s not defined on %s (%v)", opstr, arg0Src, arg0) 2268 } 2269 } 2270 ret.Src = expr 2271 p.stk.Ret(2, ret) 2272 return p 2273 } 2274 2275 func checkNamed(typ types.Type) (ret *types.Named, ok bool) { 2276 if t, ok := typ.(*types.Pointer); ok { 2277 typ = t.Elem() 2278 } 2279 ret, ok = typ.(*types.Named) 2280 return 2281 } 2282 2283 var ( 2284 unaryOps = [...]string{ 2285 token.SUB: "Neg", 2286 token.ADD: "Dup", 2287 token.XOR: "Not", 2288 token.NOT: "LNot", 2289 token.ARROW: "Recv", 2290 token.AND: "Addr", 2291 } 2292 binaryOps = [...]string{ 2293 token.ADD: "Add", // + 2294 token.SUB: "Sub", // - 2295 token.MUL: "Mul", // * 2296 token.QUO: "Quo", // / 2297 token.REM: "Rem", // % 2298 2299 token.AND: "And", // & 2300 token.OR: "Or", // | 2301 token.XOR: "Xor", // ^ 2302 token.AND_NOT: "AndNot", // &^ 2303 token.SHL: "Lsh", // << 2304 token.SHR: "Rsh", // >> 2305 2306 token.LAND: "LAnd", // && 2307 token.LOR: "LOr", // || 2308 2309 token.LSS: "LT", 2310 token.LEQ: "LE", 2311 token.GTR: "GT", 2312 token.GEQ: "GE", 2313 token.EQL: "EQ", 2314 token.NEQ: "NE", 2315 2316 xtoken.SRARROW: "PointTo", // -> 2317 xtoken.BIDIARROW: "PointBi", // <> 2318 } 2319 ) 2320 2321 // CompareNil func 2322 func (p *CodeBuilder) CompareNil(op token.Token, src ...ast.Node) *CodeBuilder { 2323 return p.Val(nil).BinaryOp(op) 2324 } 2325 2326 // Send func 2327 func (p *CodeBuilder) Send() *CodeBuilder { 2328 if debugInstr { 2329 log.Println("Send") 2330 } 2331 val := p.stk.Pop() 2332 ch := p.stk.Pop() 2333 // TODO: check types 2334 p.emitStmt(&ast.SendStmt{Chan: ch.Val, Value: val.Val}) 2335 return p 2336 } 2337 2338 // Defer func 2339 func (p *CodeBuilder) Defer() *CodeBuilder { 2340 if debugInstr { 2341 log.Println("Defer") 2342 } 2343 arg := p.stk.Pop() 2344 call, ok := arg.Val.(*ast.CallExpr) 2345 if !ok { 2346 panic("TODO: please use defer callExpr()") 2347 } 2348 p.emitStmt(&ast.DeferStmt{Call: call}) 2349 return p 2350 } 2351 2352 // Go func 2353 func (p *CodeBuilder) Go() *CodeBuilder { 2354 if debugInstr { 2355 log.Println("Go") 2356 } 2357 arg := p.stk.Pop() 2358 call, ok := arg.Val.(*ast.CallExpr) 2359 if !ok { 2360 panic("TODO: please use go callExpr()") 2361 } 2362 p.emitStmt(&ast.GoStmt{Call: call}) 2363 return p 2364 } 2365 2366 // Block starts a block statement. 2367 func (p *CodeBuilder) Block(src ...ast.Node) *CodeBuilder { 2368 if debugInstr { 2369 log.Println("Block") 2370 } 2371 stmt := &blockStmt{} 2372 p.startBlockStmt(stmt, src, "block statement", &stmt.old) 2373 return p 2374 } 2375 2376 // VBlock starts a vblock statement. 2377 func (p *CodeBuilder) VBlock() *CodeBuilder { 2378 if debugInstr { 2379 log.Println("VBlock") 2380 } 2381 stmt := &vblockStmt{} 2382 p.startVBlockStmt(stmt, "vblock statement", &stmt.old) 2383 return p 2384 } 2385 2386 // InVBlock checks if current statement is in vblock or not. 2387 func (p *CodeBuilder) InVBlock() bool { 2388 _, ok := p.current.codeBlock.(*vblockStmt) 2389 return ok 2390 } 2391 2392 // Block starts a if statement. 2393 func (p *CodeBuilder) If(src ...ast.Node) *CodeBuilder { 2394 if debugInstr { 2395 log.Println("If") 2396 } 2397 stmt := &ifStmt{} 2398 p.startBlockStmt(stmt, src, "if statement", &stmt.old) 2399 return p 2400 } 2401 2402 // Then starts body of a if/switch/for/case statement. 2403 func (p *CodeBuilder) Then(src ...ast.Node) *CodeBuilder { 2404 if debugInstr { 2405 log.Println("Then") 2406 } 2407 if flow, ok := p.current.codeBlock.(controlFlow); ok { 2408 flow.Then(p, src...) 2409 return p 2410 } 2411 panic("use if..then or switch..then or for..then please") 2412 } 2413 2414 // Else starts else body of a if..else statement. 2415 func (p *CodeBuilder) Else(src ...ast.Node) *CodeBuilder { 2416 if debugInstr { 2417 log.Println("Else") 2418 } 2419 if flow, ok := p.current.codeBlock.(*ifStmt); ok { 2420 flow.Else(p, src...) 2421 return p 2422 } 2423 panic("use if..else please") 2424 } 2425 2426 // TypeSwitch starts a type switch statement. 2427 // 2428 // <pre> 2429 // typeSwitch(name) init; expr typeAssertThen 2430 // type1, type2, ... typeN typeCase(N) 2431 // 2432 // ... 2433 // end 2434 // 2435 // type1, type2, ... typeM typeCase(M) 2436 // 2437 // ... 2438 // end 2439 // 2440 // end 2441 // </pre> 2442 func (p *CodeBuilder) TypeSwitch(name string, src ...ast.Node) *CodeBuilder { 2443 if debugInstr { 2444 log.Println("TypeSwitch") 2445 } 2446 stmt := &typeSwitchStmt{name: name} 2447 p.startBlockStmt(stmt, src, "type switch statement", &stmt.old) 2448 return p 2449 } 2450 2451 // TypeAssert func 2452 func (p *CodeBuilder) TypeAssert(typ types.Type, twoValue bool, src ...ast.Node) *CodeBuilder { 2453 if debugInstr { 2454 log.Println("TypeAssert", typ, twoValue) 2455 } 2456 arg := p.stk.Get(-1) 2457 xType, ok := p.checkInterface(arg.Type) 2458 if !ok { 2459 text, pos := p.loadExpr(getSrc(src)) 2460 p.panicCodeErrorf( 2461 pos, "invalid type assertion: %s (non-interface type %v on left)", text, arg.Type) 2462 } 2463 if missing := p.missingMethod(typ, xType); missing != "" { 2464 pos := getSrcPos(getSrc(src)) 2465 p.panicCodeErrorf( 2466 pos, "impossible type assertion:\n\t%v does not implement %v (missing %s method)", 2467 typ, arg.Type, missing) 2468 } 2469 pkg := p.pkg 2470 ret := &ast.TypeAssertExpr{X: arg.Val, Type: toType(pkg, typ)} 2471 if twoValue { 2472 tyRet := types.NewTuple( 2473 pkg.NewParam(token.NoPos, "", typ), 2474 pkg.NewParam(token.NoPos, "", types.Typ[types.Bool])) 2475 p.stk.Ret(1, &internal.Elem{Type: tyRet, Val: ret}) 2476 } else { 2477 p.stk.Ret(1, &internal.Elem{Type: typ, Val: ret}) 2478 } 2479 return p 2480 } 2481 2482 func (p *CodeBuilder) missingMethod(T types.Type, V *types.Interface) (missing string) { 2483 p.ensureLoaded(T) 2484 if m, _ := types.MissingMethod(T, V, false); m != nil { 2485 missing = m.Name() 2486 } 2487 return 2488 } 2489 2490 func (p *CodeBuilder) checkInterface(typ types.Type) (*types.Interface, bool) { 2491 retry: 2492 switch t := typ.(type) { 2493 case *types.Interface: 2494 return t, true 2495 case *types.Named: 2496 typ = p.getUnderlying(t) 2497 goto retry 2498 } 2499 return nil, false 2500 } 2501 2502 // TypeAssertThen starts body of a type switch statement. 2503 func (p *CodeBuilder) TypeAssertThen() *CodeBuilder { 2504 if debugInstr { 2505 log.Println("TypeAssertThen") 2506 } 2507 if flow, ok := p.current.codeBlock.(*typeSwitchStmt); ok { 2508 flow.TypeAssertThen(p) 2509 return p 2510 } 2511 panic("use typeSwitch..typeAssertThen please") 2512 } 2513 2514 // TypeCase starts case body of a type switch statement. 2515 func (p *CodeBuilder) TypeCase(src ...ast.Node) *CodeBuilder { 2516 if debugInstr { 2517 log.Println("TypeCase") 2518 } 2519 if flow, ok := p.current.codeBlock.(*typeSwitchStmt); ok { 2520 flow.TypeCase(p, src...) 2521 return p 2522 } 2523 panic("use switch x.(type) .. case please") 2524 } 2525 2526 // TypeDefaultThen starts default clause of a type switch statement. 2527 func (p *CodeBuilder) TypeDefaultThen(src ...ast.Node) *CodeBuilder { 2528 return p.TypeCase(src...).Then(src...) 2529 } 2530 2531 // Select starts a select statement. 2532 func (p *CodeBuilder) Select(src ...ast.Node) *CodeBuilder { 2533 if debugInstr { 2534 log.Println("Select") 2535 } 2536 stmt := &selectStmt{} 2537 p.startBlockStmt(stmt, src, "select statement", &stmt.old) 2538 return p 2539 } 2540 2541 // CommCase starts case clause of a select statement. 2542 func (p *CodeBuilder) CommCase(src ...ast.Node) *CodeBuilder { 2543 if debugInstr { 2544 log.Println("CommCase") 2545 } 2546 if flow, ok := p.current.codeBlock.(*selectStmt); ok { 2547 flow.CommCase(p, src...) 2548 return p 2549 } 2550 panic("use select..case please") 2551 } 2552 2553 // CommDefaultThen starts default clause of a select statement. 2554 func (p *CodeBuilder) CommDefaultThen(src ...ast.Node) *CodeBuilder { 2555 return p.CommCase(src...).Then(src...) 2556 } 2557 2558 // Switch starts a switch statement. 2559 func (p *CodeBuilder) Switch(src ...ast.Node) *CodeBuilder { 2560 if debugInstr { 2561 log.Println("Switch") 2562 } 2563 stmt := &switchStmt{} 2564 p.startBlockStmt(stmt, src, "switch statement", &stmt.old) 2565 return p 2566 } 2567 2568 // Case starts case clause of a switch statement. 2569 func (p *CodeBuilder) Case(src ...ast.Node) *CodeBuilder { 2570 if debugInstr { 2571 log.Println("Case") 2572 } 2573 if flow, ok := p.current.codeBlock.(*switchStmt); ok { 2574 flow.Case(p, src...) 2575 return p 2576 } 2577 panic("use switch..case please") 2578 } 2579 2580 // DefaultThen starts default clause of a switch statement. 2581 func (p *CodeBuilder) DefaultThen(src ...ast.Node) *CodeBuilder { 2582 return p.Case(src...).Then(src...) 2583 } 2584 2585 func (p *CodeBuilder) NewLabel(pos token.Pos, name string) *Label { 2586 if p.current.fn == nil { 2587 panic(p.newCodeError(pos, "syntax error: non-declaration statement outside function body")) 2588 } 2589 if old, ok := p.current.labels[name]; ok { 2590 oldPos := p.fset.Position(old.Pos()) 2591 p.handleCodeErrorf(pos, "label %s already defined at %v", name, oldPos) 2592 return nil 2593 } 2594 if p.current.labels == nil { 2595 p.current.labels = make(map[string]*Label) 2596 } 2597 l := &Label{Label: *types.NewLabel(pos, p.pkg.Types, name)} 2598 p.current.labels[name] = l 2599 return l 2600 } 2601 2602 // LookupLabel func 2603 func (p *CodeBuilder) LookupLabel(name string) (l *Label, ok bool) { 2604 l, ok = p.current.labels[name] 2605 return 2606 } 2607 2608 // Label func 2609 func (p *CodeBuilder) Label(l *Label) *CodeBuilder { 2610 name := l.Name() 2611 if debugInstr { 2612 log.Println("Label", name) 2613 } 2614 if p.current.label != nil { 2615 p.current.label.Stmt = &ast.EmptyStmt{} 2616 p.current.stmts = append(p.current.stmts, p.current.label) 2617 } 2618 p.current.label = &ast.LabeledStmt{Label: ident(name)} 2619 return p 2620 } 2621 2622 // Goto func 2623 func (p *CodeBuilder) Goto(l *Label) *CodeBuilder { 2624 name := l.Name() 2625 if debugInstr { 2626 log.Println("Goto", name) 2627 } 2628 l.used = true 2629 p.current.flows |= flowFlagGoto 2630 p.emitStmt(&ast.BranchStmt{Tok: token.GOTO, Label: ident(name)}) 2631 return p 2632 } 2633 2634 func (p *CodeBuilder) labelFlow(flow int, l *Label) (string, *ast.Ident) { 2635 if l != nil { 2636 l.used = true 2637 p.current.flows |= (flow | flowFlagWithLabel) 2638 return l.Name(), ident(l.Name()) 2639 } 2640 p.current.flows |= flow 2641 return "", nil 2642 } 2643 2644 // Break func 2645 func (p *CodeBuilder) Break(l *Label) *CodeBuilder { 2646 name, label := p.labelFlow(flowFlagBreak, l) 2647 if debugInstr { 2648 log.Println("Break", name) 2649 } 2650 p.emitStmt(&ast.BranchStmt{Tok: token.BREAK, Label: label}) 2651 return p 2652 } 2653 2654 // Continue func 2655 func (p *CodeBuilder) Continue(l *Label) *CodeBuilder { 2656 name, label := p.labelFlow(flowFlagContinue, l) 2657 if debugInstr { 2658 log.Println("Continue", name) 2659 } 2660 p.emitStmt(&ast.BranchStmt{Tok: token.CONTINUE, Label: label}) 2661 return p 2662 } 2663 2664 // Fallthrough func 2665 func (p *CodeBuilder) Fallthrough() *CodeBuilder { 2666 if debugInstr { 2667 log.Println("Fallthrough") 2668 } 2669 if flow, ok := p.current.codeBlock.(*caseStmt); ok { 2670 flow.Fallthrough(p) 2671 return p 2672 } 2673 panic("please use fallthrough in case statement") 2674 } 2675 2676 // For func 2677 func (p *CodeBuilder) For(src ...ast.Node) *CodeBuilder { 2678 if debugInstr { 2679 log.Println("For") 2680 } 2681 stmt := &forStmt{} 2682 p.startBlockStmt(stmt, src, "for statement", &stmt.old) 2683 return p 2684 } 2685 2686 // Post func 2687 func (p *CodeBuilder) Post() *CodeBuilder { 2688 if debugInstr { 2689 log.Println("Post") 2690 } 2691 if flow, ok := p.current.codeBlock.(*forStmt); ok { 2692 flow.Post(p) 2693 return p 2694 } 2695 panic("please use Post() in for statement") 2696 } 2697 2698 // ForRange func 2699 func (p *CodeBuilder) ForRange(names ...string) *CodeBuilder { 2700 return p.ForRangeEx(names) 2701 } 2702 2703 // ForRangeEx func 2704 func (p *CodeBuilder) ForRangeEx(names []string, src ...ast.Node) *CodeBuilder { 2705 if debugInstr { 2706 log.Println("ForRange", names) 2707 } 2708 stmt := &forRangeStmt{names: names} 2709 p.startBlockStmt(stmt, src, "for range statement", &stmt.old) 2710 return p 2711 } 2712 2713 // RangeAssignThen func 2714 func (p *CodeBuilder) RangeAssignThen(pos token.Pos) *CodeBuilder { 2715 if debugInstr { 2716 log.Println("RangeAssignThen") 2717 } 2718 if flow, ok := p.current.codeBlock.(*forRangeStmt); ok { 2719 flow.RangeAssignThen(p, pos) 2720 return p 2721 } 2722 panic("please use RangeAssignThen() in for range statement") 2723 } 2724 2725 // ResetStmt resets the statement state of CodeBuilder. 2726 func (p *CodeBuilder) ResetStmt() { 2727 if debugInstr { 2728 log.Println("ResetStmt") 2729 } 2730 p.stk.SetLen(p.current.base) 2731 } 2732 2733 // EndStmt func 2734 func (p *CodeBuilder) EndStmt() *CodeBuilder { 2735 n := p.stk.Len() - p.current.base 2736 if n > 0 { 2737 if n != 1 { 2738 panic("syntax error: unexpected newline, expecting := or = or comma") 2739 } 2740 if e := p.stk.Pop(); p.noSkipConst || e.CVal == nil { // skip constant 2741 p.emitStmt(&ast.ExprStmt{X: e.Val}) 2742 } 2743 } 2744 return p 2745 } 2746 2747 // End func 2748 func (p *CodeBuilder) End(src ...ast.Node) *CodeBuilder { 2749 if debugInstr { 2750 typ := reflect.TypeOf(p.current.codeBlock) 2751 if typ.Kind() == reflect.Ptr { 2752 typ = typ.Elem() 2753 } 2754 name := strings.TrimSuffix(strings.Title(typ.Name()), "Stmt") 2755 log.Println("End //", name) 2756 if p.stk.Len() > p.current.base { 2757 panic("forget to call EndStmt()?") 2758 } 2759 } 2760 p.current.End(p, getSrc(src)) 2761 return p 2762 } 2763 2764 func (p *CodeBuilder) SetBodyHandler(handle func(body *ast.BlockStmt, kind int)) *CodeBuilder { 2765 if ini, ok := p.current.codeBlock.(interface { 2766 SetBodyHandler(func(body *ast.BlockStmt, kind int)) 2767 }); ok { 2768 ini.SetBodyHandler(handle) 2769 } 2770 return p 2771 } 2772 2773 // ResetInit resets the variable init state of CodeBuilder. 2774 func (p *CodeBuilder) ResetInit() { 2775 if debugInstr { 2776 log.Println("ResetInit") 2777 } 2778 p.valDecl = p.valDecl.resetInit(p) 2779 } 2780 2781 // EndInit func 2782 func (p *CodeBuilder) EndInit(n int) *CodeBuilder { 2783 if debugInstr { 2784 log.Println("EndInit", n) 2785 } 2786 p.valDecl = p.valDecl.endInit(p, n) 2787 return p 2788 } 2789 2790 // Debug func 2791 func (p *CodeBuilder) Debug(dbg func(cb *CodeBuilder)) *CodeBuilder { 2792 dbg(p) 2793 return p 2794 } 2795 2796 // Get func 2797 func (p *CodeBuilder) Get(idx int) *Element { 2798 return p.stk.Get(idx) 2799 } 2800 2801 // ---------------------------------------------------------------------------- 2802 2803 type InternalStack = internal.Stack 2804 2805 // InternalStack: don't call it (only for internal use) 2806 func (p *CodeBuilder) InternalStack() *InternalStack { 2807 return &p.stk 2808 } 2809 2810 // ----------------------------------------------------------------------------