github.com/goplus/gop@v1.2.6/cl/expr.go (about) 1 /* 2 * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cl 18 19 import ( 20 "bytes" 21 "errors" 22 goast "go/ast" 23 gotoken "go/token" 24 "go/types" 25 "log" 26 "math/big" 27 "strconv" 28 "strings" 29 "syscall" 30 31 "github.com/goplus/gogen" 32 "github.com/goplus/gogen/cpackages" 33 "github.com/goplus/gop/ast" 34 "github.com/goplus/gop/printer" 35 "github.com/goplus/gop/token" 36 ) 37 38 /*----------------------------------------------------------------------------- 39 40 Name context: 41 - varVal (ident) 42 - varRef = expr (identLHS) 43 - pkgRef.member (selectorExpr) 44 - pkgRef.member = expr (selectorExprLHS) 45 - pkgRef.fn(args) (callExpr) 46 - fn(args) (callExpr) 47 - spx.fn(args) (callExpr) 48 - this.member (classMember) 49 - this.method(args) (classMember) 50 51 Name lookup: 52 - local variables 53 - $recv members (only in class files) 54 - package globals (variables, constants, types, imported packages etc.) 55 - $spx package exports (only in class files) 56 - $universe package exports (including builtins) 57 58 // ---------------------------------------------------------------------------*/ 59 60 const ( 61 clIdentCanAutoCall = 1 << iota // allow auto property 62 clIdentAllowBuiltin 63 clIdentLHS 64 clIdentSelectorExpr // this ident is X (not Sel) of ast.SelectorExpr 65 clIdentGoto 66 clCallWithTwoValue 67 clCommandWithoutArgs // this expr is a command without args (eg. ls) 68 clCommandIdent // this expr is a command and an ident (eg. mkdir "abc") 69 clIdentInStringLitEx // this expr is an ident in a string extended literal (eg. ${PATH}) 70 ) 71 72 const ( 73 objNormal = iota 74 objPkgRef 75 objCPkgRef 76 objGopExecOrEnv 77 78 objGopEnv = objGopExecOrEnv 79 objGopExec = objGopExecOrEnv 80 ) 81 82 func compileIdent(ctx *blockCtx, ident *ast.Ident, flags int) (pkg gogen.PkgRef, kind int) { 83 fvalue := (flags&clIdentSelectorExpr) != 0 || (flags&clIdentLHS) == 0 84 cb := ctx.cb 85 name := ident.Name 86 if name == "_" { 87 if fvalue { 88 panic(ctx.newCodeError(ident.Pos(), "cannot use _ as value")) 89 } 90 cb.VarRef(nil) 91 return 92 } 93 94 var recv *types.Var 95 var oldo types.Object 96 scope := ctx.pkg.Types.Scope() 97 at, o := cb.Scope().LookupParent(name, token.NoPos) 98 if o != nil { 99 if at != scope && at != types.Universe { // local object 100 goto find 101 } 102 } 103 104 if ctx.isClass { // in a Go+ class file 105 if recv = classRecv(cb); recv != nil { 106 cb.Val(recv) 107 chkFlag := flags 108 if chkFlag&clIdentSelectorExpr != 0 { // TODO: remove this condition 109 chkFlag = clIdentCanAutoCall 110 } 111 if compileMember(ctx, ident, name, chkFlag) == nil { // class member object 112 return 113 } 114 cb.InternalStack().PopN(1) 115 } 116 } 117 118 // global object 119 if ctx.loadSymbol(name) { 120 o, at = scope.Lookup(name), scope 121 } 122 if o != nil && at != types.Universe { 123 goto find 124 } 125 126 // pkgRef object 127 if (flags & clIdentSelectorExpr) != 0 { 128 if name == "C" && len(ctx.clookups) > 0 { 129 kind = objCPkgRef 130 return 131 } 132 if pi, ok := ctx.findImport(name); ok { 133 if rec := ctx.recorder(); rec != nil { 134 rec.Use(ident, pi.pkgName) 135 } 136 return pi.PkgRef, objPkgRef 137 } 138 } 139 140 // function alias 141 if compileFuncAlias(ctx, scope, ident, flags) { 142 return 143 } 144 145 // object from import . "xxx" 146 if compilePkgRef(ctx, gogen.PkgRef{}, ident, flags, objPkgRef) { 147 return 148 } 149 150 // universe object 151 if obj := ctx.pkg.Builtin().TryRef(name); obj != nil { 152 if (flags&clIdentAllowBuiltin) == 0 && isBuiltin(o) && !strings.HasPrefix(o.Name(), "print") { 153 panic(ctx.newCodeErrorf(ident.Pos(), "use of builtin %s not in function call", name)) 154 } 155 oldo, o = o, obj 156 } else if o == nil { 157 // for support Gop_Exec, see TestSpxGopExec 158 if (clCommandIdent&flags) != 0 && recv != nil && gopMember(cb, recv, "Gop_Exec", ident) == nil { 159 kind = objGopExec 160 return 161 } 162 // for support Gop_Env, see TestSpxGopEnv 163 if (clIdentInStringLitEx&flags) != 0 && recv != nil && gopMember(cb, recv, "Gop_Env", ident) == nil { 164 kind = objGopEnv 165 return 166 } 167 if (clIdentGoto & flags) != 0 { 168 l := ident.Obj.Data.(*ast.Ident) 169 panic(ctx.newCodeErrorf(l.Pos(), "label %v is not defined", l.Name)) 170 } 171 panic(ctx.newCodeErrorf(ident.Pos(), "undefined: %s", name)) 172 } 173 174 find: 175 if fvalue { 176 cb.Val(o, ident) 177 } else { 178 cb.VarRef(o, ident) 179 } 180 if rec := ctx.recorder(); rec != nil { 181 e := cb.Get(-1) 182 if oldo != nil && gogen.IsTypeEx(e.Type) { // for builtin object 183 rec.recordIdent(ident, oldo) 184 return 185 } 186 rec.recordIdent(ident, o) 187 } 188 return 189 } 190 191 /* 192 func compileMatrixLit(ctx *blockCtx, v *ast.MatrixLit) { 193 cb := ctx.cb 194 ncol := -1 195 for _, elts := range v.Elts { 196 switch n := len(elts); n { 197 case 1: 198 elt := elts[0] 199 if e, ok := elt.(*ast.Ellipsis); ok { 200 compileExpr(ctx, e.Elt) 201 panic("TODO") // TODO(xsw): matrixLit with ellipsis 202 } 203 fallthrough 204 default: 205 if ncol < 0 { 206 ncol = n 207 } else if ncol != n { 208 ctx.handleErrorf(elts[0].Pos(), "inconsistent matrix column count: got %v, want %v", n, ncol) 209 } 210 for _, elt := range elts { 211 compileExpr(ctx, elt) 212 } 213 cb.SliceLitEx(...) 214 } 215 } 216 } 217 */ 218 219 func compileEnvExpr(ctx *blockCtx, v *ast.EnvExpr) { 220 cb := ctx.cb 221 if ctx.isClass { // in a Go+ class file 222 if recv := classRecv(cb); recv != nil { 223 if gopMember(cb, recv, "Gop_Env", v) == nil { 224 name := v.Name 225 cb.Val(name.Name, name).CallWith(1, 0, v) 226 return 227 } 228 } 229 } 230 invalidVal(cb) 231 ctx.handleErrorf(v.Pos(), "operator $%v undefined", v.Name) 232 } 233 234 func classRecv(cb *gogen.CodeBuilder) *types.Var { 235 if fn := cb.Func(); fn != nil { 236 sig := fn.Ancestor().Type().(*types.Signature) 237 return sig.Recv() 238 } 239 return nil 240 } 241 242 func gopMember(cb *gogen.CodeBuilder, recv *types.Var, op string, src ...ast.Node) error { 243 _, e := cb.Val(recv).Member(op, gogen.MemberFlagVal, src...) 244 return e 245 } 246 247 func isBuiltin(o types.Object) bool { 248 if _, ok := o.(*types.Builtin); ok { 249 return ok 250 } 251 return false 252 } 253 254 func compileMember(ctx *blockCtx, v ast.Node, name string, flags int) error { 255 var mflag gogen.MemberFlag 256 switch { 257 case (flags & clIdentLHS) != 0: 258 mflag = gogen.MemberFlagRef 259 case (flags & clIdentCanAutoCall) != 0: 260 mflag = gogen.MemberFlagAutoProperty 261 default: 262 mflag = gogen.MemberFlagMethodAlias 263 } 264 _, err := ctx.cb.Member(name, mflag, v) 265 return err 266 } 267 268 func compileExprLHS(ctx *blockCtx, expr ast.Expr) { 269 switch v := expr.(type) { 270 case *ast.Ident: 271 compileIdent(ctx, v, clIdentLHS) 272 case *ast.IndexExpr: 273 compileIndexExprLHS(ctx, v) 274 case *ast.SelectorExpr: 275 compileSelectorExprLHS(ctx, v) 276 case *ast.StarExpr: 277 compileStarExprLHS(ctx, v) 278 default: 279 panic(ctx.newCodeErrorf(v.Pos(), "compileExprLHS failed: unknown - %T", expr)) 280 } 281 if rec := ctx.recorder(); rec != nil { 282 rec.recordExpr(ctx, expr, true) 283 } 284 } 285 286 func twoValue(inFlags []int) bool { 287 return inFlags != nil && (inFlags[0]&clCallWithTwoValue) != 0 288 } 289 290 func identOrSelectorFlags(inFlags []int) (flags int, cmdNoArgs bool) { 291 if inFlags == nil { 292 return clIdentCanAutoCall, false 293 } 294 flags = inFlags[0] 295 if cmdNoArgs = (flags & clCommandWithoutArgs) != 0; cmdNoArgs { 296 flags &^= clCommandWithoutArgs 297 } else { 298 flags |= clIdentCanAutoCall 299 } 300 return 301 } 302 303 func callCmdNoArgs(ctx *blockCtx, src ast.Node, panicErr bool) (err error) { 304 if gogen.IsFunc(ctx.cb.InternalStack().Get(-1).Type) { 305 if err = ctx.cb.CallWithEx(0, 0, src); err != nil { 306 if panicErr { 307 panic(err) 308 } 309 } 310 } 311 return 312 } 313 314 func compileExpr(ctx *blockCtx, expr ast.Expr, inFlags ...int) { 315 switch v := expr.(type) { 316 case *ast.Ident: 317 flags, cmdNoArgs := identOrSelectorFlags(inFlags) 318 if cmdNoArgs { 319 flags |= clCommandIdent // for support Gop_Exec, see TestSpxGopExec 320 } 321 _, kind := compileIdent(ctx, v, flags) 322 if cmdNoArgs || kind == objGopExecOrEnv { 323 cb := ctx.cb 324 if kind == objGopExecOrEnv { 325 cb.Val(v.Name, v) 326 } else { 327 err := callCmdNoArgs(ctx, expr, false) 328 if err == nil { 329 return 330 } 331 if !(ctx.isClass && tryGopExec(cb, v)) { 332 panic(err) 333 } 334 } 335 cb.CallWith(1, 0, v) 336 } 337 case *ast.BasicLit: 338 compileBasicLit(ctx, v) 339 case *ast.CallExpr: 340 flags := 0 341 if inFlags != nil { 342 flags = inFlags[0] 343 } 344 compileCallExpr(ctx, v, flags) 345 case *ast.SelectorExpr: 346 flags, cmdNoArgs := identOrSelectorFlags(inFlags) 347 compileSelectorExpr(ctx, v, flags) 348 if cmdNoArgs { 349 callCmdNoArgs(ctx, expr, true) 350 return 351 } 352 case *ast.BinaryExpr: 353 compileBinaryExpr(ctx, v) 354 case *ast.UnaryExpr: 355 compileUnaryExpr(ctx, v, twoValue(inFlags)) 356 case *ast.FuncLit: 357 compileFuncLit(ctx, v) 358 case *ast.CompositeLit: 359 compileCompositeLit(ctx, v, nil, false) 360 case *ast.SliceLit: 361 compileSliceLit(ctx, v, nil) 362 case *ast.RangeExpr: 363 compileRangeExpr(ctx, v) 364 case *ast.IndexExpr: 365 compileIndexExpr(ctx, v, twoValue(inFlags)) 366 case *ast.IndexListExpr: 367 compileIndexListExpr(ctx, v, twoValue(inFlags)) 368 case *ast.SliceExpr: 369 compileSliceExpr(ctx, v) 370 case *ast.StarExpr: 371 compileStarExpr(ctx, v) 372 case *ast.ArrayType: 373 ctx.cb.Typ(toArrayType(ctx, v), v) 374 case *ast.MapType: 375 ctx.cb.Typ(toMapType(ctx, v), v) 376 case *ast.StructType: 377 ctx.cb.Typ(toStructType(ctx, v), v) 378 case *ast.ChanType: 379 ctx.cb.Typ(toChanType(ctx, v), v) 380 case *ast.InterfaceType: 381 ctx.cb.Typ(toInterfaceType(ctx, v), v) 382 case *ast.ComprehensionExpr: 383 compileComprehensionExpr(ctx, v, twoValue(inFlags)) 384 case *ast.TypeAssertExpr: 385 compileTypeAssertExpr(ctx, v, twoValue(inFlags)) 386 case *ast.ParenExpr: 387 compileExpr(ctx, v.X, inFlags...) 388 case *ast.ErrWrapExpr: 389 compileErrWrapExpr(ctx, v, 0) 390 case *ast.FuncType: 391 ctx.cb.Typ(toFuncType(ctx, v, nil, nil), v) 392 case *ast.EnvExpr: 393 compileEnvExpr(ctx, v) 394 /* case *ast.MatrixLit: 395 compileMatrixLit(ctx, v) */ 396 default: 397 panic(ctx.newCodeErrorf(v.Pos(), "compileExpr failed: unknown - %T", v)) 398 } 399 if rec := ctx.recorder(); rec != nil { 400 rec.recordExpr(ctx, expr, false) 401 } 402 } 403 404 func compileExprOrNone(ctx *blockCtx, expr ast.Expr) { 405 if expr != nil { 406 compileExpr(ctx, expr) 407 } else { 408 ctx.cb.None() 409 } 410 } 411 412 func compileUnaryExpr(ctx *blockCtx, v *ast.UnaryExpr, twoValue bool) { 413 compileExpr(ctx, v.X) 414 ctx.cb.UnaryOp(gotoken.Token(v.Op), twoValue, v) 415 } 416 417 func compileBinaryExpr(ctx *blockCtx, v *ast.BinaryExpr) { 418 compileExpr(ctx, v.X) 419 compileExpr(ctx, v.Y) 420 ctx.cb.BinaryOp(gotoken.Token(v.Op), v) 421 } 422 423 func compileIndexExprLHS(ctx *blockCtx, v *ast.IndexExpr) { 424 compileExpr(ctx, v.X) 425 compileExpr(ctx, v.Index) 426 ctx.cb.IndexRef(1, v) 427 } 428 429 func compileStarExprLHS(ctx *blockCtx, v *ast.StarExpr) { // *x = ... 430 compileExpr(ctx, v.X) 431 ctx.cb.ElemRef() 432 } 433 434 func compileStarExpr(ctx *blockCtx, v *ast.StarExpr) { // ... = *x 435 compileExpr(ctx, v.X) 436 ctx.cb.Star() 437 } 438 439 func compileTypeAssertExpr(ctx *blockCtx, v *ast.TypeAssertExpr, twoValue bool) { 440 compileExpr(ctx, v.X) 441 if v.Type == nil { 442 panic("TODO: x.(type) is only used in type switch") 443 } 444 typ := toType(ctx, v.Type) 445 ctx.cb.TypeAssert(typ, twoValue, v) 446 } 447 448 func compileIndexExpr(ctx *blockCtx, v *ast.IndexExpr, twoValue bool) { // x[i] 449 compileExpr(ctx, v.X) 450 compileExpr(ctx, v.Index) 451 ctx.cb.Index(1, twoValue, v) 452 } 453 454 func compileIndexListExpr(ctx *blockCtx, v *ast.IndexListExpr, twoValue bool) { // fn[t1,t2] 455 compileExpr(ctx, v.X) 456 n := len(v.Indices) 457 for i := 0; i < n; i++ { 458 compileExpr(ctx, v.Indices[i]) 459 } 460 ctx.cb.Index(n, twoValue, v) 461 } 462 463 func compileSliceExpr(ctx *blockCtx, v *ast.SliceExpr) { // x[i:j:k] 464 compileExpr(ctx, v.X) 465 compileExprOrNone(ctx, v.Low) 466 compileExprOrNone(ctx, v.High) 467 if v.Slice3 { 468 compileExprOrNone(ctx, v.Max) 469 } 470 ctx.cb.Slice(v.Slice3, v) 471 } 472 473 func compileSelectorExprLHS(ctx *blockCtx, v *ast.SelectorExpr) { 474 switch x := v.X.(type) { 475 case *ast.Ident: 476 if at, kind := compileIdent(ctx, x, clIdentLHS|clIdentSelectorExpr); kind != objNormal { 477 ctx.cb.VarRef(at.Ref(v.Sel.Name)) 478 return 479 } 480 default: 481 compileExpr(ctx, v.X) 482 } 483 ctx.cb.MemberRef(v.Sel.Name, v) 484 } 485 486 func compileSelectorExpr(ctx *blockCtx, v *ast.SelectorExpr, flags int) { 487 switch x := v.X.(type) { 488 case *ast.Ident: 489 if at, kind := compileIdent(ctx, x, flags|clIdentCanAutoCall|clIdentSelectorExpr); kind != objNormal { 490 if compilePkgRef(ctx, at, v.Sel, flags, kind) { 491 return 492 } 493 if token.IsExported(v.Sel.Name) { 494 panic(ctx.newCodeErrorf(x.Pos(), "undefined: %s.%s", x.Name, v.Sel.Name)) 495 } 496 panic(ctx.newCodeErrorf(x.Pos(), "cannot refer to unexported name %s.%s", x.Name, v.Sel.Name)) 497 } 498 default: 499 compileExpr(ctx, v.X) 500 } 501 if err := compileMember(ctx, v, v.Sel.Name, flags); err != nil { 502 panic(err) 503 } 504 } 505 506 func compileFuncAlias(ctx *blockCtx, scope *types.Scope, x *ast.Ident, flags int) bool { 507 name := x.Name 508 if c := name[0]; c >= 'a' && c <= 'z' { 509 name = string(rune(c)+('A'-'a')) + name[1:] 510 o := scope.Lookup(name) 511 if o == nil && ctx.loadSymbol(name) { 512 o = scope.Lookup(name) 513 } 514 if o != nil { 515 return identVal(ctx, x, flags, o, true) 516 } 517 } 518 return false 519 } 520 521 func pkgRef(at gogen.PkgRef, name string) (o types.Object, alias bool) { 522 if c := name[0]; c >= 'a' && c <= 'z' { 523 name = string(rune(c)+('A'-'a')) + name[1:] 524 if v := at.TryRef(name); v != nil && gogen.IsFunc(v.Type()) { 525 return v, true 526 } 527 return 528 } 529 return at.TryRef(name), false 530 } 531 532 // allow pkg.Types to be nil 533 func lookupPkgRef(ctx *blockCtx, pkg gogen.PkgRef, x *ast.Ident, pkgKind int) (o types.Object, alias bool) { 534 if pkg.Types != nil { 535 return pkgRef(pkg, x.Name) 536 } 537 if pkgKind == objPkgRef { 538 for _, at := range ctx.lookups { 539 if o2, alias2 := pkgRef(at, x.Name); o2 != nil { 540 if o != nil { 541 panic(ctx.newCodeErrorf( 542 x.Pos(), "confliction: %s declared both in \"%s\" and \"%s\"", 543 x.Name, at.Types.Path(), pkg.Types.Path())) 544 } 545 pkg, o, alias = at, o2, alias2 546 } 547 } 548 } else { 549 var cpkg cpackages.PkgRef 550 for _, at := range ctx.clookups { 551 if o2 := at.Lookup(x.Name); o2 != nil { 552 if o != nil { 553 panic(ctx.newCodeErrorf( 554 x.Pos(), "confliction: %s declared both in \"%s\" and \"%s\"", 555 x.Name, at.Pkg().Types.Path(), cpkg.Pkg().Types.Path())) 556 } 557 cpkg, o = at, o2 558 } 559 } 560 } 561 return 562 } 563 564 // allow at.Types to be nil 565 func compilePkgRef(ctx *blockCtx, at gogen.PkgRef, x *ast.Ident, flags, pkgKind int) bool { 566 if v, alias := lookupPkgRef(ctx, at, x, pkgKind); v != nil { 567 if (flags & clIdentLHS) != 0 { 568 if rec := ctx.recorder(); rec != nil { 569 rec.Use(x, v) 570 } 571 ctx.cb.VarRef(v, x) 572 return true 573 } 574 return identVal(ctx, x, flags, v, alias) 575 } 576 return false 577 } 578 579 func identVal(ctx *blockCtx, x *ast.Ident, flags int, v types.Object, alias bool) bool { 580 autocall := false 581 if alias { 582 if autocall = (flags & clIdentCanAutoCall) != 0; autocall { 583 if !gogen.HasAutoProperty(v.Type()) { 584 return false 585 } 586 } 587 } 588 if rec := ctx.recorder(); rec != nil { 589 rec.Use(x, v) 590 } 591 cb := ctx.cb.Val(v, x) 592 if autocall { 593 cb.CallWith(0, 0, x) 594 } 595 return true 596 } 597 598 type fnType struct { 599 next *fnType 600 params *types.Tuple 601 sig *types.Signature 602 base int 603 size int 604 variadic bool 605 typetype bool 606 typeparam bool 607 } 608 609 func (p *fnType) arg(i int, ellipsis bool) types.Type { 610 if i+p.base < p.size { 611 return p.params.At(i + p.base).Type() 612 } 613 if p.variadic { 614 t := p.params.At(p.size).Type() 615 if ellipsis { 616 return t 617 } 618 return t.(*types.Slice).Elem() 619 } 620 return nil 621 } 622 623 func (p *fnType) init(base int, t *types.Signature) { 624 p.base = base 625 p.sig = t 626 p.params, p.variadic, p.typeparam = t.Params(), t.Variadic(), t.TypeParams() != nil 627 p.size = p.params.Len() 628 if p.variadic { 629 p.size-- 630 } 631 } 632 633 func (p *fnType) initTypeType(t *gogen.TypeType) { 634 param := types.NewParam(0, nil, "", t.Type()) 635 p.params, p.typetype = types.NewTuple(param), true 636 p.size = 1 637 } 638 639 func (p *fnType) load(fnt types.Type) { 640 switch v := fnt.(type) { 641 case *gogen.TypeType: 642 p.initTypeType(v) 643 case *types.Signature: 644 typ, objs := gogen.CheckSigFuncExObjects(v) 645 switch typ.(type) { 646 case *gogen.TyOverloadFunc, *gogen.TyOverloadMethod: 647 p.initFuncs(0, objs) 648 return 649 case *gogen.TyTemplateRecvMethod: 650 p.initFuncs(1, objs) 651 return 652 } 653 p.init(0, v) 654 } 655 } 656 657 func (p *fnType) initFuncs(base int, funcs []types.Object) { 658 for i, obj := range funcs { 659 if sig, ok := obj.Type().(*types.Signature); ok { 660 if i == 0 { 661 p.init(base, sig) 662 } else { 663 fn := &fnType{} 664 fn.init(base, sig) 665 p.next = fn 666 p = p.next 667 } 668 } 669 } 670 } 671 672 func compileCallExpr(ctx *blockCtx, v *ast.CallExpr, inFlags int) { 673 var ifn *ast.Ident 674 switch fn := v.Fun.(type) { 675 case *ast.Ident: 676 if v.IsCommand() { // for support Gop_Exec, see TestSpxGopExec 677 inFlags |= clCommandIdent 678 } 679 if _, kind := compileIdent(ctx, fn, clIdentAllowBuiltin|inFlags); kind == objGopExec { 680 args := make([]ast.Expr, 1, len(v.Args)+1) 681 args[0] = toBasicLit(fn) 682 args = append(args, v.Args...) 683 v = &ast.CallExpr{Fun: fn, Args: args, Ellipsis: v.Ellipsis, NoParenEnd: v.NoParenEnd} 684 } else { 685 ifn = fn 686 } 687 case *ast.SelectorExpr: 688 compileSelectorExpr(ctx, fn, 0) 689 case *ast.ErrWrapExpr: 690 if v.IsCommand() { 691 callExpr := *v 692 callExpr.Fun = fn.X 693 ewExpr := *fn 694 ewExpr.X = &callExpr 695 compileErrWrapExpr(ctx, &ewExpr, inFlags) 696 return 697 } 698 compileErrWrapExpr(ctx, fn, 0) 699 default: 700 compileExpr(ctx, fn) 701 } 702 var err error 703 var stk = ctx.cb.InternalStack() 704 var base = stk.Len() 705 var flags gogen.InstrFlags 706 var ellipsis = v.Ellipsis != gotoken.NoPos 707 if ellipsis { 708 flags = gogen.InstrFlagEllipsis 709 } 710 if (inFlags & clCallWithTwoValue) != 0 { 711 flags |= gogen.InstrFlagTwoValue 712 } 713 pfn := stk.Get(-1) 714 fnt := pfn.Type 715 fn := &fnType{} 716 fn.load(fnt) 717 for fn != nil { 718 if err = compileCallArgs(ctx, pfn, fn, v, ellipsis, flags); err == nil { 719 if rec := ctx.recorder(); rec != nil { 720 rec.recordCallExpr(ctx, v, fnt) 721 } 722 return 723 } 724 stk.SetLen(base) 725 fn = fn.next 726 } 727 if ifn != nil && builtinOrGopExec(ctx, ifn, v, flags) == nil { 728 return 729 } 730 panic(err) 731 } 732 733 func toBasicLit(fn *ast.Ident) *ast.BasicLit { 734 return &ast.BasicLit{ValuePos: fn.NamePos, Kind: token.STRING, Value: strconv.Quote(fn.Name)} 735 } 736 737 // maybe builtin new/delete: see TestSpxNewObj, TestMayBuiltinDelete 738 // maybe Gop_Exec: see TestSpxGopExec 739 func builtinOrGopExec(ctx *blockCtx, ifn *ast.Ident, v *ast.CallExpr, flags gogen.InstrFlags) error { 740 cb := ctx.cb 741 switch name := ifn.Name; name { 742 case "new", "delete": 743 cb.InternalStack().PopN(1) 744 cb.Val(ctx.pkg.Builtin().Ref(name), ifn) 745 return fnCall(ctx, v, flags, 0) 746 default: 747 // for support Gop_Exec, see TestSpxGopExec 748 if v.IsCommand() && ctx.isClass && tryGopExec(cb, ifn) { 749 return fnCall(ctx, v, flags, 1) 750 } 751 } 752 return syscall.ENOENT 753 } 754 755 func tryGopExec(cb *gogen.CodeBuilder, ifn *ast.Ident) bool { 756 if recv := classRecv(cb); recv != nil { 757 cb.InternalStack().PopN(1) 758 if gopMember(cb, recv, "Gop_Exec", ifn) == nil { 759 cb.Val(ifn.Name, ifn) 760 return true 761 } 762 } 763 return false 764 } 765 766 func fnCall(ctx *blockCtx, v *ast.CallExpr, flags gogen.InstrFlags, extra int) error { 767 for _, arg := range v.Args { 768 compileExpr(ctx, arg) 769 } 770 return ctx.cb.CallWithEx(len(v.Args)+extra, flags, v) 771 } 772 773 func compileCallArgs(ctx *blockCtx, pfn *gogen.Element, fn *fnType, v *ast.CallExpr, ellipsis bool, flags gogen.InstrFlags) (err error) { 774 var needInferFunc bool 775 for i, arg := range v.Args { 776 switch expr := arg.(type) { 777 case *ast.LambdaExpr: 778 if fn.typeparam { 779 needInferFunc = true 780 compileIdent(ctx, ast.NewIdent("nil"), 0) 781 continue 782 } 783 sig, e := checkLambdaFuncType(ctx, expr, fn.arg(i, ellipsis), clLambaArgument, v.Fun) 784 if e != nil { 785 return e 786 } 787 if err = compileLambdaExpr(ctx, expr, sig); err != nil { 788 return 789 } 790 case *ast.LambdaExpr2: 791 if fn.typeparam { 792 needInferFunc = true 793 compileIdent(ctx, ast.NewIdent("nil"), 0) 794 continue 795 } 796 sig, e := checkLambdaFuncType(ctx, expr, fn.arg(i, ellipsis), clLambaArgument, v.Fun) 797 if e != nil { 798 return e 799 } 800 if err = compileLambdaExpr2(ctx, expr, sig); err != nil { 801 return 802 } 803 case *ast.CompositeLit: 804 if err = compileCompositeLitEx(ctx, expr, fn.arg(i, ellipsis), true); err != nil { 805 return 806 } 807 case *ast.SliceLit: 808 t := fn.arg(i, ellipsis) 809 switch t.(type) { 810 case *types.Slice: 811 case *types.Named: 812 if _, ok := getUnderlying(ctx, t).(*types.Slice); !ok { 813 t = nil 814 } 815 default: 816 t = nil 817 } 818 typetype := fn.typetype && t != nil 819 if typetype { 820 ctx.cb.InternalStack().PopN(1) 821 } 822 if err = compileSliceLit(ctx, expr, t, true); err != nil { 823 return 824 } 825 if typetype { 826 return 827 } 828 default: 829 compileExpr(ctx, arg) 830 } 831 } 832 if needInferFunc { 833 typ, err := gogen.InferFunc(ctx.pkg, pfn, fn.sig, nil, ctx.cb.InternalStack().GetArgs(len(v.Args)), flags) 834 if err != nil { 835 return err 836 } 837 next := &fnType{} 838 next.init(fn.base, typ.(*types.Signature)) 839 next.next = fn.next 840 fn.next = next 841 return errCallNext 842 } 843 return ctx.cb.CallWithEx(len(v.Args), flags, v) 844 } 845 846 var ( 847 errCallNext = errors.New("call next") 848 ) 849 850 type clLambaFlag string 851 852 const ( 853 clLambaAssign clLambaFlag = "assignment" 854 clLambaField clLambaFlag = "field value" 855 clLambaArgument clLambaFlag = "argument" 856 ) 857 858 // check lambda func type 859 func checkLambdaFuncType(ctx *blockCtx, lambda ast.Expr, ftyp types.Type, flag clLambaFlag, toNode ast.Node) (*types.Signature, error) { 860 typ := ftyp 861 retry: 862 switch t := typ.(type) { 863 case *types.Signature: 864 if l, ok := lambda.(*ast.LambdaExpr); ok { 865 if len(l.Rhs) != t.Results().Len() { 866 break 867 } 868 } 869 return t, nil 870 case *types.Named: 871 typ = t.Underlying() 872 goto retry 873 } 874 src := ctx.LoadExpr(toNode) 875 return nil, ctx.newCodeErrorf(lambda.Pos(), "cannot use lambda literal as type %v in %v to %v", ftyp, flag, src) 876 } 877 878 func compileLambda(ctx *blockCtx, lambda ast.Expr, sig *types.Signature) { 879 switch expr := lambda.(type) { 880 case *ast.LambdaExpr: 881 if err := compileLambdaExpr(ctx, expr, sig); err != nil { 882 panic(err) 883 } 884 case *ast.LambdaExpr2: 885 if err := compileLambdaExpr2(ctx, expr, sig); err != nil { 886 panic(err) 887 } 888 } 889 } 890 891 func makeLambdaParams(ctx *blockCtx, pos token.Pos, lhs []*ast.Ident, in *types.Tuple) (*types.Tuple, error) { 892 pkg := ctx.pkg 893 n := len(lhs) 894 if nin := in.Len(); n != nin { 895 fewOrMany := "few" 896 if n > nin { 897 fewOrMany = "many" 898 } 899 has := make([]string, n) 900 for i, v := range lhs { 901 has[i] = v.Name 902 } 903 return nil, ctx.newCodeErrorf( 904 pos, "too %s arguments in lambda expression\n\thave (%s)\n\twant %v", fewOrMany, strings.Join(has, ", "), in) 905 } 906 if n == 0 { 907 return nil, nil 908 } 909 params := make([]*types.Var, n) 910 for i, name := range lhs { 911 param := pkg.NewParam(name.Pos(), name.Name, in.At(i).Type()) 912 params[i] = param 913 if rec := ctx.recorder(); rec != nil { 914 rec.Def(name, param) 915 } 916 } 917 return types.NewTuple(params...), nil 918 } 919 920 func makeLambdaResults(pkg *gogen.Package, out *types.Tuple) *types.Tuple { 921 nout := out.Len() 922 if nout == 0 { 923 return nil 924 } 925 results := make([]*types.Var, nout) 926 for i := 0; i < nout; i++ { 927 results[i] = pkg.NewParam(token.NoPos, "", out.At(i).Type()) 928 } 929 return types.NewTuple(results...) 930 } 931 932 func compileLambdaExpr(ctx *blockCtx, v *ast.LambdaExpr, sig *types.Signature) error { 933 pkg := ctx.pkg 934 params, err := makeLambdaParams(ctx, v.Pos(), v.Lhs, sig.Params()) 935 if err != nil { 936 return err 937 } 938 results := makeLambdaResults(pkg, sig.Results()) 939 ctx.cb.NewClosure(params, results, false).BodyStart(pkg) 940 if len(v.Lhs) > 0 { 941 defNames(ctx, v.Lhs, ctx.cb.Scope()) 942 } 943 for _, v := range v.Rhs { 944 compileExpr(ctx, v) 945 } 946 if rec := ctx.recorder(); rec != nil { 947 rec.Scope(v, ctx.cb.Scope()) 948 } 949 ctx.cb.Return(len(v.Rhs)).End(v) 950 return nil 951 } 952 953 func compileLambdaExpr2(ctx *blockCtx, v *ast.LambdaExpr2, sig *types.Signature) error { 954 pkg := ctx.pkg 955 params, err := makeLambdaParams(ctx, v.Pos(), v.Lhs, sig.Params()) 956 if err != nil { 957 return err 958 } 959 results := makeLambdaResults(pkg, sig.Results()) 960 comments, once := ctx.cb.BackupComments() 961 fn := ctx.cb.NewClosure(params, results, false) 962 cb := fn.BodyStart(ctx.pkg, v.Body) 963 if len(v.Lhs) > 0 { 964 defNames(ctx, v.Lhs, cb.Scope()) 965 } 966 compileStmts(ctx, v.Body.List) 967 if rec := ctx.recorder(); rec != nil { 968 rec.Scope(v, ctx.cb.Scope()) 969 } 970 cb.End(v) 971 ctx.cb.SetComments(comments, once) 972 return nil 973 } 974 975 func compileFuncLit(ctx *blockCtx, v *ast.FuncLit) { 976 cb := ctx.cb 977 comments, once := cb.BackupComments() 978 sig := toFuncType(ctx, v.Type, nil, nil) 979 if rec := ctx.recorder(); rec != nil { 980 rec.recordFuncLit(v, sig) 981 } 982 fn := cb.NewClosureWith(sig) 983 if body := v.Body; body != nil { 984 loadFuncBody(ctx, fn, body, nil, v) 985 cb.SetComments(comments, once) 986 } 987 } 988 989 func compileBasicLit(ctx *blockCtx, v *ast.BasicLit) { 990 cb := ctx.cb 991 switch v.Kind { 992 case token.RAT: 993 val := v.Value 994 bi, _ := new(big.Int).SetString(val[:len(val)-1], 10) // remove r suffix 995 cb.UntypedBigInt(bi, v) 996 case token.CSTRING: 997 s, err := strconv.Unquote(v.Value) 998 if err != nil { 999 log.Panicln("compileBasicLit:", err) 1000 } 1001 n := len(s) 1002 tyInt8 := types.Typ[types.Int8] 1003 typ := types.NewArray(tyInt8, int64(n+1)) 1004 cb.Typ(types.NewPointer(tyInt8)).Typ(types.Typ[types.UnsafePointer]) 1005 for i := 0; i < n; i++ { 1006 cb.Val(rune(s[i])) 1007 } 1008 cb.Val(rune(0)).ArrayLit(typ, n+1).UnaryOp(gotoken.AND).Call(1).Call(1) 1009 default: 1010 if v.Extra == nil { 1011 basicLit(cb, v) 1012 return 1013 } 1014 compileStringLitEx(ctx, cb, v) 1015 } 1016 } 1017 1018 func invalidVal(cb *gogen.CodeBuilder) { 1019 cb.Val(&gogen.Element{Type: types.Typ[types.Invalid]}) 1020 } 1021 1022 func basicLit(cb *gogen.CodeBuilder, v *ast.BasicLit) { 1023 cb.Val(&goast.BasicLit{Kind: gotoken.Token(v.Kind), Value: v.Value}, v) 1024 } 1025 1026 const ( 1027 stringutilPkgPath = "github.com/qiniu/x/stringutil" 1028 ) 1029 1030 func compileStringLitEx(ctx *blockCtx, cb *gogen.CodeBuilder, lit *ast.BasicLit) { 1031 pos := lit.ValuePos + 1 1032 quote := lit.Value[:1] 1033 parts := lit.Extra.Parts 1034 n := len(parts) 1035 if n != 1 { 1036 cb.Val(ctx.pkg.Import(stringutilPkgPath).Ref("Concat")) 1037 } 1038 for _, part := range parts { 1039 switch v := part.(type) { 1040 case string: // normal string literal or end with "$$" 1041 next := pos + token.Pos(len(v)) 1042 if strings.HasSuffix(v, "$$") { 1043 v = v[:len(v)-1] 1044 } 1045 basicLit(cb, &ast.BasicLit{ValuePos: pos - 1, Value: quote + v + quote, Kind: token.STRING}) 1046 pos = next 1047 case ast.Expr: 1048 flags := 0 1049 if _, ok := v.(*ast.Ident); ok { 1050 flags = clIdentInStringLitEx 1051 } 1052 compileExpr(ctx, v, flags) 1053 t := cb.Get(-1).Type 1054 if t.Underlying() != types.Typ[types.String] { 1055 if _, err := cb.Member("string", gogen.MemberFlagAutoProperty); err != nil { 1056 if e, ok := err.(*gogen.CodeError); ok { 1057 err = ctx.newCodeErrorf(v.Pos(), "%s.string%s", ctx.LoadExpr(v), e.Msg) 1058 } 1059 ctx.handleErr(err) 1060 } 1061 } 1062 pos = v.End() 1063 default: 1064 panic("compileStringLitEx TODO: unexpected part") 1065 } 1066 } 1067 if n != 1 { 1068 cb.CallWith(n, 0, lit) 1069 } 1070 } 1071 1072 const ( 1073 compositeLitVal = 0 1074 compositeLitKeyVal = 1 1075 ) 1076 1077 func checkCompositeLitElts(elts []ast.Expr) (kind int) { 1078 for _, elt := range elts { 1079 if _, ok := elt.(*ast.KeyValueExpr); ok { 1080 return compositeLitKeyVal 1081 } 1082 } 1083 return compositeLitVal 1084 } 1085 1086 func compileCompositeLitElts(ctx *blockCtx, elts []ast.Expr, kind int, expected *kvType) { 1087 for _, elt := range elts { 1088 if kv, ok := elt.(*ast.KeyValueExpr); ok { 1089 if key, ok := kv.Key.(*ast.CompositeLit); ok && key.Type == nil { 1090 compileCompositeLit(ctx, key, expected.Key(), false) 1091 } else { 1092 compileExpr(ctx, kv.Key) 1093 } 1094 if val, ok := kv.Value.(*ast.CompositeLit); ok && val.Type == nil { 1095 compileCompositeLit(ctx, val, expected.Elem(), false) 1096 } else { 1097 compileExpr(ctx, kv.Value) 1098 } 1099 } else { 1100 if kind == compositeLitKeyVal { 1101 ctx.cb.None() 1102 } 1103 if val, ok := elt.(*ast.CompositeLit); ok && val.Type == nil { 1104 compileCompositeLit(ctx, val, expected.Elem(), false) 1105 } else { 1106 compileExpr(ctx, elt) 1107 } 1108 } 1109 } 1110 } 1111 1112 func compileStructLitInKeyVal(ctx *blockCtx, elts []ast.Expr, t *types.Struct, typ types.Type, src *ast.CompositeLit) error { 1113 for _, elt := range elts { 1114 kv := elt.(*ast.KeyValueExpr) 1115 name := kv.Key.(*ast.Ident) 1116 idx := lookupField(t, name.Name) 1117 if idx >= 0 { 1118 ctx.cb.Val(idx) 1119 } else { 1120 src := ctx.LoadExpr(name) 1121 return ctx.newCodeErrorf(name.Pos(), "%s undefined (type %v has no field or method %s)", src, typ, name.Name) 1122 } 1123 if rec := ctx.recorder(); rec != nil { 1124 rec.Use(name, t.Field(idx)) 1125 } 1126 switch expr := kv.Value.(type) { 1127 case *ast.LambdaExpr, *ast.LambdaExpr2: 1128 sig, err := checkLambdaFuncType(ctx, expr, t.Field(idx).Type(), clLambaField, kv.Key) 1129 if err != nil { 1130 return err 1131 } 1132 compileLambda(ctx, expr, sig) 1133 default: 1134 compileExpr(ctx, kv.Value) 1135 } 1136 } 1137 ctx.cb.StructLit(typ, len(elts)<<1, true, src) 1138 return nil 1139 } 1140 1141 func lookupField(t *types.Struct, name string) int { 1142 for i, n := 0, t.NumFields(); i < n; i++ { 1143 if fld := t.Field(i); fld.Name() == name { 1144 return i 1145 } 1146 } 1147 return -1 1148 } 1149 1150 type kvType struct { 1151 underlying types.Type 1152 key, val types.Type 1153 cached bool 1154 } 1155 1156 func (p *kvType) required() *kvType { 1157 if !p.cached { 1158 p.cached = true 1159 switch t := p.underlying.(type) { 1160 case *types.Slice: 1161 p.key, p.val = types.Typ[types.Int], t.Elem() 1162 case *types.Array: 1163 p.key, p.val = types.Typ[types.Int], t.Elem() 1164 case *types.Map: 1165 p.key, p.val = t.Key(), t.Elem() 1166 } 1167 } 1168 return p 1169 } 1170 1171 func (p *kvType) Key() types.Type { 1172 return p.required().key 1173 } 1174 1175 func (p *kvType) Elem() types.Type { 1176 return p.required().val 1177 } 1178 1179 func getUnderlying(ctx *blockCtx, typ types.Type) types.Type { 1180 u := typ.Underlying() 1181 if u == nil { 1182 if t, ok := typ.(*types.Named); ok { 1183 ctx.loadNamed(ctx.pkg, t) 1184 u = t.Underlying() 1185 } 1186 } 1187 return u 1188 } 1189 1190 func compileCompositeLit(ctx *blockCtx, v *ast.CompositeLit, expected types.Type, mapOrStructOnly bool) { 1191 if err := compileCompositeLitEx(ctx, v, expected, mapOrStructOnly); err != nil { 1192 panic(err) 1193 } 1194 } 1195 1196 // mapOrStructOnly means only map/struct can omit type 1197 func compileCompositeLitEx(ctx *blockCtx, v *ast.CompositeLit, expected types.Type, mapOrStructOnly bool) error { 1198 var hasPtr bool 1199 var typ, underlying types.Type 1200 var kind = checkCompositeLitElts(v.Elts) 1201 if v.Type != nil { 1202 typ = toType(ctx, v.Type) 1203 underlying = getUnderlying(ctx, typ) 1204 } else if expected != nil { 1205 if t, ok := expected.(*types.Pointer); ok { 1206 telem := t.Elem() 1207 tu := getUnderlying(ctx, telem) 1208 if _, ok := tu.(*types.Struct); ok { // struct pointer 1209 typ, underlying, hasPtr = telem, tu, true 1210 } 1211 } else if tu := getUnderlying(ctx, expected); !mapOrStructOnly || isMapOrStruct(tu) { 1212 typ, underlying = expected, tu 1213 } 1214 } 1215 if t, ok := underlying.(*types.Struct); ok && kind == compositeLitKeyVal { 1216 if err := compileStructLitInKeyVal(ctx, v.Elts, t, typ, v); err != nil { 1217 return err 1218 } 1219 } else { 1220 compileCompositeLitElts(ctx, v.Elts, kind, &kvType{underlying: underlying}) 1221 n := len(v.Elts) 1222 if isMap(underlying) { 1223 if kind == compositeLitVal && n > 0 { 1224 return ctx.newCodeError(v.Pos(), "missing key in map literal") 1225 } 1226 if err := ctx.cb.MapLitEx(typ, n<<1, v); err != nil { 1227 return err 1228 } 1229 } else { 1230 switch underlying.(type) { 1231 case *types.Slice: 1232 ctx.cb.SliceLitEx(typ, n<<kind, kind == compositeLitKeyVal, v) 1233 case *types.Array: 1234 ctx.cb.ArrayLitEx(typ, n<<kind, kind == compositeLitKeyVal, v) 1235 case *types.Struct: 1236 ctx.cb.StructLit(typ, n, false, v) // key-val mode handled by compileStructLitInKeyVal 1237 default: 1238 return ctx.newCodeErrorf(v.Pos(), "invalid composite literal type %v", typ) 1239 } 1240 } 1241 } 1242 if hasPtr { 1243 ctx.cb.UnaryOp(gotoken.AND) 1244 typ = expected 1245 } 1246 if rec := ctx.recorder(); rec != nil { 1247 rec.recordCompositeLit(v, typ) 1248 } 1249 return nil 1250 } 1251 1252 func isMap(tu types.Type) bool { 1253 if tu == nil { // map can omit type 1254 return true 1255 } 1256 _, ok := tu.(*types.Map) 1257 return ok 1258 } 1259 1260 func isMapOrStruct(tu types.Type) bool { 1261 switch tu.(type) { 1262 case *types.Struct: 1263 return true 1264 case *types.Map: 1265 return true 1266 } 1267 return false 1268 } 1269 1270 func compileSliceLit(ctx *blockCtx, v *ast.SliceLit, typ types.Type, noPanic ...bool) (err error) { 1271 if noPanic != nil { 1272 defer func() { 1273 if e := recover(); e != nil { // TODO: don't use defer to capture error 1274 err = ctx.recoverErr(e, v) 1275 } 1276 }() 1277 } 1278 n := len(v.Elts) 1279 for _, elt := range v.Elts { 1280 compileExpr(ctx, elt) 1281 } 1282 if sliceHasTypeParam(ctx, typ) { 1283 ctx.cb.SliceLitEx(nil, n, false, v) 1284 } else { 1285 ctx.cb.SliceLitEx(typ, n, false, v) 1286 } 1287 return 1288 } 1289 1290 func compileRangeExpr(ctx *blockCtx, v *ast.RangeExpr) { 1291 pkg, cb := ctx.pkg, ctx.cb 1292 cb.Val(pkg.Builtin().Ref("newRange")) 1293 if v.First == nil { 1294 ctx.cb.Val(0, v) 1295 } else { 1296 compileExpr(ctx, v.First) 1297 } 1298 compileExpr(ctx, v.Last) 1299 if v.Expr3 == nil { 1300 ctx.cb.Val(1, v) 1301 } else { 1302 compileExpr(ctx, v.Expr3) 1303 } 1304 cb.Call(3) 1305 } 1306 1307 const ( 1308 comprehensionInvalid = iota 1309 comprehensionList 1310 comprehensionMap 1311 comprehensionSelect 1312 ) 1313 1314 func comprehensionKind(v *ast.ComprehensionExpr) int { 1315 switch v.Tok { 1316 case token.LBRACK: // [ 1317 return comprehensionList 1318 case token.LBRACE: // { 1319 if _, ok := v.Elt.(*ast.KeyValueExpr); ok { 1320 return comprehensionMap 1321 } 1322 return comprehensionSelect 1323 } 1324 panic("TODO: invalid comprehensionExpr") 1325 } 1326 1327 // [expr for k, v <- container, cond] 1328 // {for k, v <- container, cond} 1329 // {expr for k, v <- container, cond} 1330 // {kexpr: vexpr for k, v <- container, cond} 1331 func compileComprehensionExpr(ctx *blockCtx, v *ast.ComprehensionExpr, twoValue bool) { 1332 kind := comprehensionKind(v) 1333 pkg, cb := ctx.pkg, ctx.cb 1334 var results *types.Tuple 1335 var ret *gogen.Param 1336 if v.Elt == nil { 1337 boolean := pkg.NewParam(token.NoPos, "_gop_ok", types.Typ[types.Bool]) 1338 results = types.NewTuple(boolean) 1339 } else { 1340 ret = pkg.NewAutoParam("_gop_ret") 1341 if kind == comprehensionSelect && twoValue { 1342 boolean := pkg.NewParam(token.NoPos, "_gop_ok", types.Typ[types.Bool]) 1343 results = types.NewTuple(ret, boolean) 1344 } else { 1345 results = types.NewTuple(ret) 1346 } 1347 } 1348 cb.NewClosure(nil, results, false).BodyStart(pkg) 1349 if kind == comprehensionMap { 1350 cb.VarRef(ret).ZeroLit(ret.Type()).Assign(1) 1351 } 1352 end := 0 1353 for i := len(v.Fors) - 1; i >= 0; i-- { 1354 names := make([]string, 0, 2) 1355 defineNames := make([]*ast.Ident, 0, 2) 1356 forStmt := v.Fors[i] 1357 if forStmt.Key != nil { 1358 names = append(names, forStmt.Key.Name) 1359 defineNames = append(defineNames, forStmt.Key) 1360 } else { 1361 names = append(names, "_") 1362 } 1363 names = append(names, forStmt.Value.Name) 1364 defineNames = append(defineNames, forStmt.Value) 1365 cb.ForRange(names...) 1366 compileExpr(ctx, forStmt.X) 1367 cb.RangeAssignThen(forStmt.TokPos) 1368 defNames(ctx, defineNames, cb.Scope()) 1369 if rec := ctx.recorder(); rec != nil { 1370 rec.Scope(forStmt, cb.Scope()) 1371 } 1372 if forStmt.Cond != nil { 1373 cb.If() 1374 if forStmt.Init != nil { 1375 compileStmt(ctx, forStmt.Init) 1376 } 1377 compileExpr(ctx, forStmt.Cond) 1378 cb.Then() 1379 end++ 1380 } 1381 end++ 1382 } 1383 switch kind { 1384 case comprehensionList: 1385 // _gop_ret = append(_gop_ret, elt) 1386 cb.VarRef(ret) 1387 cb.Val(pkg.Builtin().Ref("append")) 1388 cb.Val(ret) 1389 compileExpr(ctx, v.Elt) 1390 cb.Call(2).Assign(1) 1391 case comprehensionMap: 1392 // _gop_ret[key] = val 1393 cb.Val(ret) 1394 kv := v.Elt.(*ast.KeyValueExpr) 1395 compileExpr(ctx, kv.Key) 1396 cb.IndexRef(1) 1397 compileExpr(ctx, kv.Value) 1398 cb.Assign(1) 1399 default: 1400 if v.Elt == nil { 1401 // return true 1402 cb.Val(true) 1403 cb.Return(1) 1404 } else { 1405 // return elt, true 1406 compileExpr(ctx, v.Elt) 1407 n := 1 1408 if twoValue { 1409 cb.Val(true) 1410 n++ 1411 } 1412 cb.Return(n) 1413 } 1414 } 1415 for i := 0; i < end; i++ { 1416 cb.End() 1417 } 1418 cb.Return(0).End().Call(0) 1419 } 1420 1421 const ( 1422 errorPkgPath = "github.com/qiniu/x/errors" 1423 ) 1424 1425 var ( 1426 tyError = types.Universe.Lookup("error").Type() 1427 ) 1428 1429 func compileErrWrapExpr(ctx *blockCtx, v *ast.ErrWrapExpr, inFlags int) { 1430 pkg, cb := ctx.pkg, ctx.cb 1431 useClosure := v.Tok == token.NOT || v.Default != nil 1432 if !useClosure && (cb.Scope().Parent() == types.Universe) { 1433 panic("TODO: can't use expr? in global") 1434 } 1435 1436 compileExpr(ctx, v.X, inFlags) 1437 x := cb.InternalStack().Pop() 1438 n := 0 1439 results, ok := x.Type.(*types.Tuple) 1440 if ok { 1441 n = results.Len() - 1 1442 } 1443 1444 var ret []*types.Var 1445 if n > 0 { 1446 i, retName := 0, "_gop_ret" 1447 ret = make([]*gogen.Param, n) 1448 for { 1449 ret[i] = pkg.NewAutoParam(retName) 1450 i++ 1451 if i >= n { 1452 break 1453 } 1454 retName = "_gop_ret" + strconv.Itoa(i+1) 1455 } 1456 } 1457 sig := types.NewSignatureType(nil, nil, nil, nil, types.NewTuple(ret...), false) 1458 if useClosure { 1459 cb.NewClosureWith(sig).BodyStart(pkg) 1460 } else { 1461 cb.CallInlineClosureStart(sig, 0, false) 1462 } 1463 1464 cb.NewVar(tyError, "_gop_err") 1465 err := cb.Scope().Lookup("_gop_err") 1466 1467 for _, retVar := range ret { 1468 cb.VarRef(retVar) 1469 } 1470 cb.VarRef(err) 1471 cb.InternalStack().Push(x) 1472 cb.Assign(n+1, 1) 1473 1474 cb.If().Val(err).CompareNil(gotoken.NEQ).Then() 1475 if v.Default == nil { 1476 pos := pkg.Fset.Position(v.Pos()) 1477 currentFunc := ctx.cb.Func().Ancestor() 1478 const newFrameArgs = 5 1479 1480 currentFuncName := currentFunc.Name() 1481 if currentFuncName == "" { 1482 currentFuncName = "main" 1483 } 1484 1485 currentFuncName = strings.Join([]string{currentFunc.Pkg().Name(), currentFuncName}, ".") 1486 1487 cb. 1488 VarRef(err). 1489 Val(pkg.Import(errorPkgPath).Ref("NewFrame")). 1490 Val(err). 1491 Val(sprintAst(pkg.Fset, v.X)). 1492 Val(relFile(ctx.relBaseDir, pos.Filename)). 1493 Val(pos.Line). 1494 Val(currentFuncName). 1495 Call(newFrameArgs). 1496 Assign(1) 1497 } 1498 1499 if v.Tok == token.NOT { // expr! 1500 cb.Val(pkg.Builtin().Ref("panic")).Val(err).Call(1).EndStmt() 1501 } else if v.Default == nil { // expr? 1502 cb.Val(err).ReturnErr(true) 1503 } else { // expr?:val 1504 compileExpr(ctx, v.Default) 1505 cb.Return(1) 1506 } 1507 cb.End().Return(0).End() 1508 if useClosure { 1509 cb.Call(0) 1510 } 1511 } 1512 1513 func sprintAst(fset *token.FileSet, x ast.Node) string { 1514 var buf bytes.Buffer 1515 err := printer.Fprint(&buf, fset, x) 1516 if err != nil { 1517 panic("Unexpected error: " + err.Error()) 1518 } 1519 1520 return buf.String() 1521 } 1522 1523 // -----------------------------------------------------------------------------