github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/compiler/expressions.go (about) 1 package compiler 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/ast" 7 "go/constant" 8 "go/token" 9 "go/types" 10 "sort" 11 "strconv" 12 "strings" 13 14 "github.com/goplusjs/gopherjs/compiler/analysis" 15 "github.com/goplusjs/gopherjs/compiler/astutil" 16 "github.com/goplusjs/gopherjs/compiler/typesutil" 17 ) 18 19 type expression struct { 20 str string 21 parens bool 22 } 23 24 func (e *expression) String() string { 25 return e.str 26 } 27 28 func (e *expression) StringWithParens() string { 29 if e.parens { 30 return "(" + e.str + ")" 31 } 32 return e.str 33 } 34 35 func (c *funcContext) translateExpr(expr ast.Expr) *expression { 36 exprType := c.p.TypeOf(expr) 37 if value := c.p.Types[expr].Value; value != nil { 38 basic := exprType.Underlying().(*types.Basic) 39 switch { 40 case isBoolean(basic): 41 return c.formatExpr("%s", strconv.FormatBool(constant.BoolVal(value))) 42 case isInteger(basic): 43 if is64Bit(basic) { 44 if basic.Kind() == types.Int64 { 45 d, ok := constant.Int64Val(constant.ToInt(value)) 46 if !ok { 47 panic("could not get exact uint") 48 } 49 return c.formatExpr("new %s(%s, %s)", c.typeName(exprType), strconv.FormatInt(d>>32, 10), strconv.FormatUint(uint64(d)&(1<<32-1), 10)) 50 } 51 d, ok := constant.Uint64Val(constant.ToInt(value)) 52 if !ok { 53 panic("could not get exact uint") 54 } 55 return c.formatExpr("new %s(%s, %s)", c.typeName(exprType), strconv.FormatUint(d>>32, 10), strconv.FormatUint(d&(1<<32-1), 10)) 56 } 57 d, ok := constant.Int64Val(constant.ToInt(value)) 58 if !ok { 59 panic("could not get exact int") 60 } 61 return c.formatExpr("%s", strconv.FormatInt(d, 10)) 62 case isFloat(basic): 63 f, _ := constant.Float64Val(value) 64 return c.formatExpr("%s", strconv.FormatFloat(f, 'g', -1, 64)) 65 case isComplex(basic): 66 r, _ := constant.Float64Val(constant.Real(value)) 67 i, _ := constant.Float64Val(constant.Imag(value)) 68 if basic.Kind() == types.UntypedComplex { 69 exprType = types.Typ[types.Complex128] 70 } 71 return c.formatExpr("new %s(%s, %s)", c.typeName(exprType), strconv.FormatFloat(r, 'g', -1, 64), strconv.FormatFloat(i, 'g', -1, 64)) 72 case isString(basic): 73 return c.formatExpr("%s", encodeString(constant.StringVal(value))) 74 default: 75 panic("Unhandled constant type: " + basic.String()) 76 } 77 } 78 79 var obj types.Object 80 switch e := expr.(type) { 81 case *ast.SelectorExpr: 82 obj = c.p.Uses[e.Sel] 83 case *ast.Ident: 84 obj = c.p.Defs[e] 85 if obj == nil { 86 obj = c.p.Uses[e] 87 } 88 } 89 90 if obj != nil && typesutil.IsJsPackage(obj.Pkg()) { 91 switch obj.Name() { 92 case "Global": 93 return c.formatExpr("$global") 94 case "Module": 95 return c.formatExpr("$module") 96 case "Undefined": 97 return c.formatExpr("undefined") 98 } 99 } 100 101 switch e := expr.(type) { 102 case *ast.CompositeLit: 103 if ptrType, isPointer := exprType.(*types.Pointer); isPointer { 104 exprType = ptrType.Elem() 105 } 106 107 collectIndexedElements := func(elementType types.Type) []string { 108 var elements []string 109 i := 0 110 zero := c.translateExpr(c.zeroValue(elementType)).String() 111 for _, element := range e.Elts { 112 if kve, isKve := element.(*ast.KeyValueExpr); isKve { 113 key, ok := constant.Int64Val(constant.ToInt(c.p.Types[kve.Key].Value)) 114 if !ok { 115 panic("could not get exact int") 116 } 117 i = int(key) 118 element = kve.Value 119 } 120 for len(elements) <= i { 121 elements = append(elements, zero) 122 } 123 elements[i] = c.translateImplicitConversionWithCloning(element, elementType).String() 124 i++ 125 } 126 return elements 127 } 128 129 switch t := exprType.Underlying().(type) { 130 case *types.Array: 131 elements := collectIndexedElements(t.Elem()) 132 if len(elements) == 0 { 133 return c.formatExpr("%s.zero()", c.typeName(t)) 134 } 135 zero := c.translateExpr(c.zeroValue(t.Elem())).String() 136 for len(elements) < int(t.Len()) { 137 elements = append(elements, zero) 138 } 139 return c.formatExpr(`$toNativeArray(%s, [%s])`, typeKind(t.Elem()), strings.Join(elements, ", ")) 140 case *types.Slice: 141 return c.formatExpr("new %s([%s])", c.typeName(exprType), strings.Join(collectIndexedElements(t.Elem()), ", ")) 142 case *types.Map: 143 entries := make([]string, len(e.Elts)) 144 for i, element := range e.Elts { 145 kve := element.(*ast.KeyValueExpr) 146 entries[i] = fmt.Sprintf("{ k: %s, v: %s }", c.translateImplicitConversionWithCloning(kve.Key, t.Key()), c.translateImplicitConversionWithCloning(kve.Value, t.Elem())) 147 } 148 return c.formatExpr("$makeMap(%s.keyFor, [%s])", c.typeName(t.Key()), strings.Join(entries, ", ")) 149 case *types.Struct: 150 elements := make([]string, t.NumFields()) 151 isKeyValue := true 152 if len(e.Elts) != 0 { 153 _, isKeyValue = e.Elts[0].(*ast.KeyValueExpr) 154 } 155 if !isKeyValue { 156 for i, element := range e.Elts { 157 elements[i] = c.translateImplicitConversionWithCloning(element, t.Field(i).Type()).String() 158 } 159 } 160 if isKeyValue { 161 for i := range elements { 162 elements[i] = c.translateExpr(c.zeroValue(t.Field(i).Type())).String() 163 } 164 for _, element := range e.Elts { 165 kve := element.(*ast.KeyValueExpr) 166 for j := range elements { 167 if kve.Key.(*ast.Ident).Name == t.Field(j).Name() { 168 elements[j] = c.translateImplicitConversionWithCloning(kve.Value, t.Field(j).Type()).String() 169 break 170 } 171 } 172 } 173 } 174 return c.formatExpr("new %s.ptr(%s)", c.typeName(exprType), strings.Join(elements, ", ")) 175 default: 176 panic(fmt.Sprintf("Unhandled CompositeLit type: %T\n", t)) 177 } 178 179 case *ast.FuncLit: 180 _, fun := translateFunction(e.Type, nil, e.Body, c, exprType.(*types.Signature), c.p.FuncLitInfos[e], "") 181 if len(c.p.escapingVars) != 0 { 182 names := make([]string, 0, len(c.p.escapingVars)) 183 for obj := range c.p.escapingVars { 184 names = append(names, c.p.objectNames[obj]) 185 } 186 sort.Strings(names) 187 list := strings.Join(names, ", ") 188 return c.formatExpr("(function(%s) { return %s; })(%s)", list, fun, list) 189 } 190 return c.formatExpr("(%s)", fun) 191 192 case *ast.UnaryExpr: 193 t := c.p.TypeOf(e.X) 194 switch e.Op { 195 case token.AND: 196 if typesutil.IsJsObject(exprType) { 197 return c.formatExpr("%e.object", e.X) 198 } 199 200 switch t.Underlying().(type) { 201 case *types.Struct, *types.Array: 202 return c.translateExpr(e.X) 203 } 204 205 switch x := astutil.RemoveParens(e.X).(type) { 206 case *ast.CompositeLit: 207 return c.formatExpr("$newDataPointer(%e, %s)", x, c.typeName(c.p.TypeOf(e))) 208 case *ast.Ident: 209 obj := c.p.Uses[x].(*types.Var) 210 if c.p.escapingVars[obj] { 211 return c.formatExpr("(%1s.$ptr || (%1s.$ptr = new %2s(function() { return this.$target[0]; }, function($v) { this.$target[0] = $v; }, %1s)))", c.p.objectNames[obj], c.typeName(exprType)) 212 } 213 return c.formatExpr(`(%1s || (%1s = new %2s(function() { return %3s; }, function($v) { %4s })))`, c.varPtrName(obj), c.typeName(exprType), c.objectName(obj), c.translateAssign(x, c.newIdent("$v", exprType), false)) 214 case *ast.SelectorExpr: 215 sel, ok := c.p.SelectionOf(x) 216 if !ok { 217 // qualified identifier 218 obj := c.p.Uses[x.Sel].(*types.Var) 219 return c.formatExpr(`(%1s || (%1s = new %2s(function() { return %3s; }, function($v) { %4s })))`, c.varPtrName(obj), c.typeName(exprType), c.objectName(obj), c.translateAssign(x, c.newIdent("$v", exprType), false)) 220 } 221 newSel := &ast.SelectorExpr{X: c.newIdent("this.$target", c.p.TypeOf(x.X)), Sel: x.Sel} 222 c.setType(newSel, exprType) 223 c.p.additionalSelections[newSel] = sel 224 return c.formatExpr("(%1e.$ptr_%2s || (%1e.$ptr_%2s = new %3s(function() { return %4e; }, function($v) { %5s }, %1e)))", x.X, x.Sel.Name, c.typeName(exprType), newSel, c.translateAssign(newSel, c.newIdent("$v", exprType), false)) 225 case *ast.IndexExpr: 226 if _, ok := c.p.TypeOf(x.X).Underlying().(*types.Slice); ok { 227 return c.formatExpr("$indexPtr(%1e.$array, %1e.$offset + %2e, %3s)", x.X, x.Index, c.typeName(exprType)) 228 } 229 return c.formatExpr("$indexPtr(%e, %e, %s)", x.X, x.Index, c.typeName(exprType)) 230 case *ast.StarExpr: 231 return c.translateExpr(x.X) 232 default: 233 panic(fmt.Sprintf("Unhandled: %T\n", x)) 234 } 235 236 case token.ARROW: 237 call := &ast.CallExpr{ 238 Fun: c.newIdent("$recv", types.NewSignature(nil, types.NewTuple(types.NewVar(0, nil, "", t)), types.NewTuple(types.NewVar(0, nil, "", exprType), types.NewVar(0, nil, "", types.Typ[types.Bool])), false)), 239 Args: []ast.Expr{e.X}, 240 } 241 c.Blocking[call] = true 242 if _, isTuple := exprType.(*types.Tuple); isTuple { 243 return c.formatExpr("%e", call) 244 } 245 return c.formatExpr("%e[0]", call) 246 } 247 248 basic := t.Underlying().(*types.Basic) 249 switch e.Op { 250 case token.ADD: 251 return c.translateExpr(e.X) 252 case token.SUB: 253 switch { 254 case is64Bit(basic): 255 return c.formatExpr("new %1s(-%2h, -%2l)", c.typeName(t), e.X) 256 case isComplex(basic): 257 return c.formatExpr("new %1s(-%2r, -%2i)", c.typeName(t), e.X) 258 case isUnsigned(basic): 259 return c.fixNumber(c.formatExpr("-%e", e.X), basic) 260 default: 261 return c.formatExpr("-%e", e.X) 262 } 263 case token.XOR: 264 if is64Bit(basic) { 265 return c.formatExpr("new %1s(~%2h, ~%2l >>> 0)", c.typeName(t), e.X) 266 } 267 return c.fixNumber(c.formatExpr("~%e", e.X), basic) 268 case token.NOT: 269 return c.formatExpr("!%e", e.X) 270 default: 271 panic(e.Op) 272 } 273 274 case *ast.BinaryExpr: 275 if e.Op == token.NEQ { 276 return c.formatExpr("!(%s)", c.translateExpr(&ast.BinaryExpr{ 277 X: e.X, 278 Op: token.EQL, 279 Y: e.Y, 280 })) 281 } 282 283 t := c.p.TypeOf(e.X) 284 t2 := c.p.TypeOf(e.Y) 285 _, isInterface := t2.Underlying().(*types.Interface) 286 if isInterface || types.Identical(t, types.Typ[types.UntypedNil]) { 287 t = t2 288 } 289 290 if basic, isBasic := t.Underlying().(*types.Basic); isBasic && isNumeric(basic) { 291 if is64Bit(basic) { 292 switch e.Op { 293 case token.MUL: 294 return c.formatExpr("$mul64(%e, %e)", e.X, e.Y) 295 case token.QUO: 296 return c.formatExpr("$div64(%e, %e, false)", e.X, e.Y) 297 case token.REM: 298 return c.formatExpr("$div64(%e, %e, true)", e.X, e.Y) 299 case token.SHL: 300 return c.formatExpr("$shiftLeft64(%e, %f)", e.X, e.Y) 301 case token.SHR: 302 return c.formatExpr("$shiftRight%s(%e, %f)", toJavaScriptType(basic), e.X, e.Y) 303 case token.EQL: 304 return c.formatExpr("(%1h === %2h && %1l === %2l)", e.X, e.Y) 305 case token.LSS: 306 return c.formatExpr("(%1h < %2h || (%1h === %2h && %1l < %2l))", e.X, e.Y) 307 case token.LEQ: 308 return c.formatExpr("(%1h < %2h || (%1h === %2h && %1l <= %2l))", e.X, e.Y) 309 case token.GTR: 310 return c.formatExpr("(%1h > %2h || (%1h === %2h && %1l > %2l))", e.X, e.Y) 311 case token.GEQ: 312 return c.formatExpr("(%1h > %2h || (%1h === %2h && %1l >= %2l))", e.X, e.Y) 313 case token.ADD, token.SUB: 314 return c.formatExpr("new %3s(%1h %4t %2h, %1l %4t %2l)", e.X, e.Y, c.typeName(t), e.Op) 315 case token.AND, token.OR, token.XOR: 316 return c.formatExpr("new %3s(%1h %4t %2h, (%1l %4t %2l) >>> 0)", e.X, e.Y, c.typeName(t), e.Op) 317 case token.AND_NOT: 318 return c.formatExpr("new %3s(%1h & ~%2h, (%1l & ~%2l) >>> 0)", e.X, e.Y, c.typeName(t)) 319 default: 320 panic(e.Op) 321 } 322 } 323 324 if isComplex(basic) { 325 switch e.Op { 326 case token.EQL: 327 return c.formatExpr("(%1r === %2r && %1i === %2i)", e.X, e.Y) 328 case token.ADD, token.SUB: 329 return c.formatExpr("new %3s(%1r %4t %2r, %1i %4t %2i)", e.X, e.Y, c.typeName(t), e.Op) 330 case token.MUL: 331 return c.formatExpr("new %3s(%1r * %2r - %1i * %2i, %1r * %2i + %1i * %2r)", e.X, e.Y, c.typeName(t)) 332 case token.QUO: 333 return c.formatExpr("$divComplex(%e, %e)", e.X, e.Y) 334 default: 335 panic(e.Op) 336 } 337 } 338 339 switch e.Op { 340 case token.EQL: 341 return c.formatParenExpr("%e === %e", e.X, e.Y) 342 case token.LSS, token.LEQ, token.GTR, token.GEQ: 343 return c.formatExpr("%e %t %e", e.X, e.Op, e.Y) 344 case token.ADD, token.SUB: 345 return c.fixNumber(c.formatExpr("%e %t %e", e.X, e.Op, e.Y), basic) 346 case token.MUL: 347 switch basic.Kind() { 348 case types.Int32, types.Int: 349 return c.formatParenExpr("$imul(%e, %e)", e.X, e.Y) 350 case types.Uint32, types.Uintptr: 351 return c.formatParenExpr("$imul(%e, %e) >>> 0", e.X, e.Y) 352 } 353 return c.fixNumber(c.formatExpr("%e * %e", e.X, e.Y), basic) 354 case token.QUO: 355 if isInteger(basic) { 356 // cut off decimals 357 shift := ">>" 358 if isUnsigned(basic) { 359 shift = ">>>" 360 } 361 return c.formatExpr(`(%1s = %2e / %3e, (%1s === %1s && %1s !== 1/0 && %1s !== -1/0) ? %1s %4s 0 : $throwRuntimeError("integer divide by zero"))`, c.newVariable("_q"), e.X, e.Y, shift) 362 } 363 if basic.Kind() == types.Float32 { 364 return c.fixNumber(c.formatExpr("%e / %e", e.X, e.Y), basic) 365 } 366 return c.formatExpr("%e / %e", e.X, e.Y) 367 case token.REM: 368 return c.formatExpr(`(%1s = %2e %% %3e, %1s === %1s ? %1s : $throwRuntimeError("integer divide by zero"))`, c.newVariable("_r"), e.X, e.Y) 369 case token.SHL, token.SHR: 370 op := e.Op.String() 371 if e.Op == token.SHR && isUnsigned(basic) { 372 op = ">>>" 373 } 374 if v := c.p.Types[e.Y].Value; v != nil { 375 i, _ := constant.Uint64Val(constant.ToInt(v)) 376 if i >= 32 { 377 return c.formatExpr("0") 378 } 379 return c.fixNumber(c.formatExpr("%e %s %s", e.X, op, strconv.FormatUint(i, 10)), basic) 380 } 381 if e.Op == token.SHR && !isUnsigned(basic) { 382 return c.fixNumber(c.formatParenExpr("%e >> $min(%f, 31)", e.X, e.Y), basic) 383 } 384 y := c.newVariable("y") 385 return c.fixNumber(c.formatExpr("(%s = %f, %s < 32 ? (%e %s %s) : 0)", y, e.Y, y, e.X, op, y), basic) 386 case token.AND, token.OR: 387 if isUnsigned(basic) { 388 return c.formatParenExpr("(%e %t %e) >>> 0", e.X, e.Op, e.Y) 389 } 390 return c.formatParenExpr("%e %t %e", e.X, e.Op, e.Y) 391 case token.AND_NOT: 392 return c.fixNumber(c.formatParenExpr("%e & ~%e", e.X, e.Y), basic) 393 case token.XOR: 394 return c.fixNumber(c.formatParenExpr("%e ^ %e", e.X, e.Y), basic) 395 default: 396 panic(e.Op) 397 } 398 } 399 400 switch e.Op { 401 case token.ADD, token.LSS, token.LEQ, token.GTR, token.GEQ: 402 return c.formatExpr("%e %t %e", e.X, e.Op, e.Y) 403 case token.LAND: 404 if c.Blocking[e.Y] { 405 skipCase := c.caseCounter 406 c.caseCounter++ 407 resultVar := c.newVariable("_v") 408 c.Printf("if (!(%s)) { %s = false; $s = %d; continue s; }", c.translateExpr(e.X), resultVar, skipCase) 409 c.Printf("%s = %s; case %d:", resultVar, c.translateExpr(e.Y), skipCase) 410 return c.formatExpr("%s", resultVar) 411 } 412 return c.formatExpr("%e && %e", e.X, e.Y) 413 case token.LOR: 414 if c.Blocking[e.Y] { 415 skipCase := c.caseCounter 416 c.caseCounter++ 417 resultVar := c.newVariable("_v") 418 c.Printf("if (%s) { %s = true; $s = %d; continue s; }", c.translateExpr(e.X), resultVar, skipCase) 419 c.Printf("%s = %s; case %d:", resultVar, c.translateExpr(e.Y), skipCase) 420 return c.formatExpr("%s", resultVar) 421 } 422 return c.formatExpr("%e || %e", e.X, e.Y) 423 case token.EQL: 424 switch u := t.Underlying().(type) { 425 case *types.Array, *types.Struct: 426 return c.formatExpr("$equal(%e, %e, %s)", e.X, e.Y, c.typeName(t)) 427 case *types.Interface: 428 return c.formatExpr("$interfaceIsEqual(%s, %s)", c.translateImplicitConversion(e.X, t), c.translateImplicitConversion(e.Y, t)) 429 case *types.Pointer: 430 if _, ok := u.Elem().Underlying().(*types.Array); ok { 431 return c.formatExpr("$equal(%s, %s, %s)", c.translateImplicitConversion(e.X, t), c.translateImplicitConversion(e.Y, t), c.typeName(u.Elem())) 432 } 433 case *types.Basic: 434 if isBoolean(u) { 435 if b, ok := analysis.BoolValue(e.X, c.p.Info.Info); ok && b { 436 return c.translateExpr(e.Y) 437 } 438 if b, ok := analysis.BoolValue(e.Y, c.p.Info.Info); ok && b { 439 return c.translateExpr(e.X) 440 } 441 } 442 } 443 return c.formatExpr("%s === %s", c.translateImplicitConversion(e.X, t), c.translateImplicitConversion(e.Y, t)) 444 default: 445 panic(e.Op) 446 } 447 448 case *ast.ParenExpr: 449 return c.formatParenExpr("%e", e.X) 450 451 case *ast.IndexExpr: 452 switch t := c.p.TypeOf(e.X).Underlying().(type) { 453 case *types.Array, *types.Pointer: 454 pattern := rangeCheck("%1e[%2f]", c.p.Types[e.Index].Value != nil, true) 455 if _, ok := t.(*types.Pointer); ok { // check pointer for nix (attribute getter causes a panic) 456 pattern = `(%1e.nilCheck, ` + pattern + `)` 457 } 458 return c.formatExpr(pattern, e.X, e.Index) 459 case *types.Slice: 460 return c.formatExpr(rangeCheck("%1e.$array[%1e.$offset + %2f]", c.p.Types[e.Index].Value != nil, false), e.X, e.Index) 461 case *types.Map: 462 if typesutil.IsJsObject(c.p.TypeOf(e.Index)) { 463 c.p.errList = append(c.p.errList, types.Error{Fset: c.p.fileSet, Pos: e.Index.Pos(), Msg: "cannot use js.Object as map key"}) 464 } 465 key := fmt.Sprintf("%s.keyFor(%s)", c.typeName(t.Key()), c.translateImplicitConversion(e.Index, t.Key())) 466 if _, isTuple := exprType.(*types.Tuple); isTuple { 467 return c.formatExpr(`(%1s = %2e[%3s], %1s !== undefined ? [%1s.v, true] : [%4e, false])`, c.newVariable("_entry"), e.X, key, c.zeroValue(t.Elem())) 468 } 469 return c.formatExpr(`(%1s = %2e[%3s], %1s !== undefined ? %1s.v : %4e)`, c.newVariable("_entry"), e.X, key, c.zeroValue(t.Elem())) 470 case *types.Basic: 471 return c.formatExpr("%e.charCodeAt(%f)", e.X, e.Index) 472 default: 473 panic(fmt.Sprintf("Unhandled IndexExpr: %T\n", t)) 474 } 475 476 case *ast.SliceExpr: 477 if b, isBasic := c.p.TypeOf(e.X).Underlying().(*types.Basic); isBasic && isString(b) { 478 switch { 479 case e.Low == nil && e.High == nil: 480 return c.translateExpr(e.X) 481 case e.Low == nil: 482 return c.formatExpr("$substring(%e, 0, %f)", e.X, e.High) 483 case e.High == nil: 484 return c.formatExpr("$substring(%e, %f)", e.X, e.Low) 485 default: 486 return c.formatExpr("$substring(%e, %f, %f)", e.X, e.Low, e.High) 487 } 488 } 489 slice := c.translateConversionToSlice(e.X, exprType) 490 switch { 491 case e.Low == nil && e.High == nil: 492 return c.formatExpr("%s", slice) 493 case e.Low == nil: 494 if e.Max != nil { 495 return c.formatExpr("$subslice(%s, 0, %f, %f)", slice, e.High, e.Max) 496 } 497 return c.formatExpr("$subslice(%s, 0, %f)", slice, e.High) 498 case e.High == nil: 499 return c.formatExpr("$subslice(%s, %f)", slice, e.Low) 500 default: 501 if e.Max != nil { 502 return c.formatExpr("$subslice(%s, %f, %f, %f)", slice, e.Low, e.High, e.Max) 503 } 504 return c.formatExpr("$subslice(%s, %f, %f)", slice, e.Low, e.High) 505 } 506 507 case *ast.SelectorExpr: 508 sel, ok := c.p.SelectionOf(e) 509 if !ok { 510 // qualified identifier 511 return c.formatExpr("%s", c.objectName(obj)) 512 } 513 514 switch sel.Kind() { 515 case types.FieldVal: 516 fields, jsTag := c.translateSelection(sel, e.Pos()) 517 if jsTag != "" { 518 if _, ok := sel.Type().(*types.Signature); ok { 519 return c.formatExpr("$internalize(%1e.%2s%3s, %4s, %1e.%2s)", e.X, strings.Join(fields, "."), formatJSStructTagVal(jsTag), c.typeName(sel.Type())) 520 } 521 return c.internalize(c.formatExpr("%e.%s%s", e.X, strings.Join(fields, "."), formatJSStructTagVal(jsTag)), sel.Type()) 522 } 523 return c.formatExpr("%e.%s", e.X, strings.Join(fields, ".")) 524 case types.MethodVal: 525 return c.formatExpr(`$methodVal(%s, "%s")`, c.makeReceiver(e), sel.Obj().(*types.Func).Name()) 526 case types.MethodExpr: 527 if !sel.Obj().Exported() { 528 c.p.dependencies[sel.Obj()] = true 529 } 530 if _, ok := sel.Recv().Underlying().(*types.Interface); ok { 531 return c.formatExpr(`$ifaceMethodExpr("%s")`, sel.Obj().(*types.Func).Name()) 532 } 533 return c.formatExpr(`$methodExpr(%s, "%s")`, c.typeName(sel.Recv()), sel.Obj().(*types.Func).Name()) 534 default: 535 panic(fmt.Sprintf("unexpected sel.Kind(): %T", sel.Kind())) 536 } 537 538 case *ast.CallExpr: 539 plainFun := astutil.RemoveParens(e.Fun) 540 541 if astutil.IsTypeExpr(plainFun, c.p.Info.Info) { 542 return c.formatExpr("(%s)", c.translateConversion(e.Args[0], c.p.TypeOf(plainFun))) 543 } 544 545 sig := c.p.TypeOf(plainFun).Underlying().(*types.Signature) 546 547 switch f := plainFun.(type) { 548 case *ast.Ident: 549 obj := c.p.Uses[f] 550 if o, ok := obj.(*types.Builtin); ok { 551 return c.translateBuiltin(o.Name(), sig, e.Args, e.Ellipsis.IsValid()) 552 } 553 if typesutil.IsJsPackage(obj.Pkg()) && obj.Name() == "InternalObject" { 554 return c.translateExpr(e.Args[0]) 555 } 556 return c.translateCall(e, sig, c.translateExpr(f)) 557 558 case *ast.SelectorExpr: 559 sel, ok := c.p.SelectionOf(f) 560 if !ok { 561 // qualified identifier 562 obj := c.p.Uses[f.Sel] 563 if typesutil.IsJsPackage(obj.Pkg()) { 564 switch obj.Name() { 565 case "Debugger": 566 return c.formatExpr("debugger") 567 case "InternalObject": 568 return c.translateExpr(e.Args[0]) 569 } 570 } 571 return c.translateCall(e, sig, c.translateExpr(f)) 572 } 573 574 externalizeExpr := func(e ast.Expr) string { 575 t := c.p.TypeOf(e) 576 if types.Identical(t, types.Typ[types.UntypedNil]) { 577 return "null" 578 } 579 return c.externalize(c.translateExpr(e).String(), t) 580 } 581 externalizeArgs := func(args []ast.Expr) string { 582 s := make([]string, len(args)) 583 for i, arg := range args { 584 s[i] = externalizeExpr(arg) 585 } 586 return strings.Join(s, ", ") 587 } 588 589 switch sel.Kind() { 590 case types.MethodVal: 591 recv := c.makeReceiver(f) 592 declaredFuncRecv := sel.Obj().(*types.Func).Type().(*types.Signature).Recv().Type() 593 if typesutil.IsJsObject(declaredFuncRecv) { 594 globalRef := func(id string) string { 595 if recv.String() == "$global" && id[0] == '$' && len(id) > 1 { 596 return id 597 } 598 return recv.String() + "." + id 599 } 600 switch sel.Obj().Name() { 601 case "Get": 602 if id, ok := c.identifierConstant(e.Args[0]); ok { 603 return c.formatExpr("%s", globalRef(id)) 604 } 605 return c.formatExpr("%s[$externalize(%e, $String)]", recv, e.Args[0]) 606 case "Set": 607 if id, ok := c.identifierConstant(e.Args[0]); ok { 608 return c.formatExpr("%s = %s", globalRef(id), externalizeExpr(e.Args[1])) 609 } 610 return c.formatExpr("%s[$externalize(%e, $String)] = %s", recv, e.Args[0], externalizeExpr(e.Args[1])) 611 case "Delete": 612 return c.formatExpr("delete %s[$externalize(%e, $String)]", recv, e.Args[0]) 613 case "Length": 614 return c.formatExpr("$parseInt(%s.length)", recv) 615 case "Index": 616 return c.formatExpr("%s[%e]", recv, e.Args[0]) 617 case "SetIndex": 618 return c.formatExpr("%s[%e] = %s", recv, e.Args[0], externalizeExpr(e.Args[1])) 619 case "Call": 620 if id, ok := c.identifierConstant(e.Args[0]); ok { 621 if e.Ellipsis.IsValid() { 622 objVar := c.newVariable("obj") 623 return c.formatExpr("(%s = %s, %s.%s.apply(%s, %s))", objVar, recv, objVar, id, objVar, externalizeExpr(e.Args[1])) 624 } 625 return c.formatExpr("%s(%s)", globalRef(id), externalizeArgs(e.Args[1:])) 626 } 627 if e.Ellipsis.IsValid() { 628 objVar := c.newVariable("obj") 629 return c.formatExpr("(%s = %s, %s[$externalize(%e, $String)].apply(%s, %s))", objVar, recv, objVar, e.Args[0], objVar, externalizeExpr(e.Args[1])) 630 } 631 return c.formatExpr("%s[$externalize(%e, $String)](%s)", recv, e.Args[0], externalizeArgs(e.Args[1:])) 632 case "Invoke": 633 if e.Ellipsis.IsValid() { 634 return c.formatExpr("%s.apply(undefined, %s)", recv, externalizeExpr(e.Args[0])) 635 } 636 return c.formatExpr("%s(%s)", recv, externalizeArgs(e.Args)) 637 case "New": 638 if e.Ellipsis.IsValid() { 639 return c.formatExpr("new ($global.Function.prototype.bind.apply(%s, [undefined].concat(%s)))", recv, externalizeExpr(e.Args[0])) 640 } 641 return c.formatExpr("new (%s)(%s)", recv, externalizeArgs(e.Args)) 642 case "Bool": 643 return c.internalize(recv, types.Typ[types.Bool]) 644 case "String": 645 return c.internalize(recv, types.Typ[types.String]) 646 case "Int": 647 return c.internalize(recv, types.Typ[types.Int]) 648 case "Int64": 649 return c.internalize(recv, types.Typ[types.Int64]) 650 case "Uint64": 651 return c.internalize(recv, types.Typ[types.Uint64]) 652 case "Float": 653 return c.internalize(recv, types.Typ[types.Float64]) 654 case "Interface": 655 return c.internalize(recv, types.NewInterface(nil, nil)) 656 case "Unsafe": 657 return recv 658 default: 659 panic("Invalid js package object: " + sel.Obj().Name()) 660 } 661 } 662 663 methodName := sel.Obj().Name() 664 if reservedKeywords[methodName] { 665 methodName += "$" 666 } 667 return c.translateCall(e, sig, c.formatExpr("%s.%s", recv, methodName)) 668 669 case types.FieldVal: 670 fields, jsTag := c.translateSelection(sel, f.Pos()) 671 if jsTag != "" { 672 call := c.formatExpr("%e.%s%s(%s)", f.X, strings.Join(fields, "."), formatJSStructTagVal(jsTag), externalizeArgs(e.Args)) 673 switch sig.Results().Len() { 674 case 0: 675 return call 676 case 1: 677 return c.internalize(call, sig.Results().At(0).Type()) 678 default: 679 c.p.errList = append(c.p.errList, types.Error{Fset: c.p.fileSet, Pos: f.Pos(), Msg: "field with js tag can not have func type with multiple results"}) 680 } 681 } 682 return c.translateCall(e, sig, c.formatExpr("%e.%s", f.X, strings.Join(fields, "."))) 683 684 case types.MethodExpr: 685 return c.translateCall(e, sig, c.translateExpr(f)) 686 687 default: 688 panic(fmt.Sprintf("unexpected sel.Kind(): %T", sel.Kind())) 689 } 690 default: 691 return c.translateCall(e, sig, c.translateExpr(plainFun)) 692 } 693 694 case *ast.StarExpr: 695 if typesutil.IsJsObject(c.p.TypeOf(e.X)) { 696 return c.formatExpr("new $jsObjectPtr(%e)", e.X) 697 } 698 if c1, isCall := e.X.(*ast.CallExpr); isCall && len(c1.Args) == 1 { 699 if c2, isCall := c1.Args[0].(*ast.CallExpr); isCall && len(c2.Args) == 1 && types.Identical(c.p.TypeOf(c2.Fun), types.Typ[types.UnsafePointer]) { 700 if unary, isUnary := c2.Args[0].(*ast.UnaryExpr); isUnary && unary.Op == token.AND { 701 return c.translateExpr(unary.X) // unsafe conversion 702 } 703 } 704 } 705 switch exprType.Underlying().(type) { 706 case *types.Struct, *types.Array: 707 return c.translateExpr(e.X) 708 } 709 return c.formatExpr("%e.$get()", e.X) 710 711 case *ast.TypeAssertExpr: 712 if e.Type == nil { 713 return c.translateExpr(e.X) 714 } 715 t := c.p.TypeOf(e.Type) 716 if _, isTuple := exprType.(*types.Tuple); isTuple { 717 return c.formatExpr("$assertType(%e, %s, true)", e.X, c.typeName(t)) 718 } 719 return c.formatExpr("$assertType(%e, %s)", e.X, c.typeName(t)) 720 721 case *ast.Ident: 722 if e.Name == "_" { 723 panic("Tried to translate underscore identifier.") 724 } 725 switch o := obj.(type) { 726 case *types.Var, *types.Const: 727 return c.formatExpr("%s", c.objectName(o)) 728 case *types.Func: 729 return c.formatExpr("%s", c.objectName(o)) 730 case *types.TypeName: 731 return c.formatExpr("%s", c.typeName(o.Type())) 732 case *types.Nil: 733 if typesutil.IsJsObject(exprType) { 734 return c.formatExpr("null") 735 } 736 switch t := exprType.Underlying().(type) { 737 case *types.Basic: 738 if t.Kind() != types.UnsafePointer { 739 panic("unexpected basic type") 740 } 741 return c.formatExpr("0") 742 case *types.Slice, *types.Pointer: 743 return c.formatExpr("%s.nil", c.typeName(exprType)) 744 case *types.Chan: 745 return c.formatExpr("$chanNil") 746 case *types.Map: 747 return c.formatExpr("false") 748 case *types.Interface: 749 return c.formatExpr("$ifaceNil") 750 case *types.Signature: 751 return c.formatExpr("$throwNilPointerError") 752 default: 753 panic(fmt.Sprintf("unexpected type: %T", t)) 754 } 755 default: 756 panic(fmt.Sprintf("Unhandled object: %T\n", o)) 757 } 758 759 case nil: 760 return c.formatExpr("") 761 762 default: 763 panic(fmt.Sprintf("Unhandled expression: %T\n", e)) 764 765 } 766 } 767 768 func (c *funcContext) translateCall(e *ast.CallExpr, sig *types.Signature, fun *expression) *expression { 769 args := c.translateArgs(sig, e.Args, e.Ellipsis.IsValid()) 770 if c.Blocking[e] { 771 resumeCase := c.caseCounter 772 c.caseCounter++ 773 returnVar := "$r" 774 if sig.Results().Len() != 0 { 775 returnVar = c.newVariable("_r") 776 } 777 c.Printf("%[1]s = %[2]s(%[3]s); /* */ $s = %[4]d; case %[4]d: if($c) { $c = false; %[1]s = %[1]s.$blk(); } if (%[1]s && %[1]s.$blk !== undefined) { break s; }", returnVar, fun, strings.Join(args, ", "), resumeCase) 778 if sig.Results().Len() != 0 { 779 return c.formatExpr("%s", returnVar) 780 } 781 return c.formatExpr("") 782 } 783 return c.formatExpr("%s(%s)", fun, strings.Join(args, ", ")) 784 } 785 786 func (c *funcContext) makeReceiver(e *ast.SelectorExpr) *expression { 787 sel, _ := c.p.SelectionOf(e) 788 if !sel.Obj().Exported() { 789 c.p.dependencies[sel.Obj()] = true 790 } 791 792 x := e.X 793 recvType := sel.Recv() 794 if len(sel.Index()) > 1 { 795 for _, index := range sel.Index()[:len(sel.Index())-1] { 796 if ptr, isPtr := recvType.(*types.Pointer); isPtr { 797 recvType = ptr.Elem() 798 } 799 s := recvType.Underlying().(*types.Struct) 800 recvType = s.Field(index).Type() 801 } 802 803 fakeSel := &ast.SelectorExpr{X: x, Sel: ast.NewIdent("o")} 804 c.p.additionalSelections[fakeSel] = &fakeSelection{ 805 kind: types.FieldVal, 806 recv: sel.Recv(), 807 index: sel.Index()[:len(sel.Index())-1], 808 typ: recvType, 809 } 810 x = c.setType(fakeSel, recvType) 811 } 812 813 _, isPointer := recvType.Underlying().(*types.Pointer) 814 methodsRecvType := sel.Obj().Type().(*types.Signature).Recv().Type() 815 _, pointerExpected := methodsRecvType.(*types.Pointer) 816 if !isPointer && pointerExpected { 817 recvType = types.NewPointer(recvType) 818 x = c.setType(&ast.UnaryExpr{Op: token.AND, X: x}, recvType) 819 } 820 if isPointer && !pointerExpected { 821 x = c.setType(x, methodsRecvType) 822 } 823 824 recv := c.translateImplicitConversionWithCloning(x, methodsRecvType) 825 if isWrapped(recvType) { 826 recv = c.formatExpr("new %s(%s)", c.typeName(methodsRecvType), recv) 827 } 828 return recv 829 } 830 831 func (c *funcContext) translateBuiltin(name string, sig *types.Signature, args []ast.Expr, ellipsis bool) *expression { 832 switch name { 833 case "new": 834 t := sig.Results().At(0).Type().(*types.Pointer) 835 if c.p.Pkg.Path() == "syscall" && types.Identical(t.Elem().Underlying(), types.Typ[types.Uintptr]) { 836 return c.formatExpr("new Uint8Array(8)") 837 } 838 switch t.Elem().Underlying().(type) { 839 case *types.Struct, *types.Array: 840 return c.formatExpr("%e", c.zeroValue(t.Elem())) 841 default: 842 return c.formatExpr("$newDataPointer(%e, %s)", c.zeroValue(t.Elem()), c.typeName(t)) 843 } 844 case "make": 845 switch argType := c.p.TypeOf(args[0]).Underlying().(type) { 846 case *types.Slice: 847 t := c.typeName(c.p.TypeOf(args[0])) 848 if len(args) == 3 { 849 return c.formatExpr("$makeSlice(%s, %f, %f)", t, args[1], args[2]) 850 } 851 return c.formatExpr("$makeSlice(%s, %f)", t, args[1]) 852 case *types.Map: 853 if len(args) == 2 && c.p.Types[args[1]].Value == nil { 854 return c.formatExpr(`((%1f < 0 || %1f > 2147483647) ? $throwRuntimeError("makemap: size out of range") : {})`, args[1]) 855 } 856 return c.formatExpr("{}") 857 case *types.Chan: 858 length := "0" 859 if len(args) == 2 { 860 length = c.formatExpr("%f", args[1]).String() 861 } 862 return c.formatExpr("new $Chan(%s, %s)", c.typeName(c.p.TypeOf(args[0]).Underlying().(*types.Chan).Elem()), length) 863 default: 864 panic(fmt.Sprintf("Unhandled make type: %T\n", argType)) 865 } 866 case "len": 867 switch argType := c.p.TypeOf(args[0]).Underlying().(type) { 868 case *types.Basic: 869 return c.formatExpr("%e.length", args[0]) 870 case *types.Slice: 871 return c.formatExpr("%e.$length", args[0]) 872 case *types.Pointer: 873 return c.formatExpr("(%e, %d)", args[0], argType.Elem().(*types.Array).Len()) 874 case *types.Map: 875 return c.formatExpr("$keys(%e).length", args[0]) 876 case *types.Chan: 877 return c.formatExpr("%e.$buffer.length", args[0]) 878 // length of array is constant 879 default: 880 panic(fmt.Sprintf("Unhandled len type: %T\n", argType)) 881 } 882 case "cap": 883 switch argType := c.p.TypeOf(args[0]).Underlying().(type) { 884 case *types.Slice, *types.Chan: 885 return c.formatExpr("%e.$capacity", args[0]) 886 case *types.Pointer: 887 return c.formatExpr("(%e, %d)", args[0], argType.Elem().(*types.Array).Len()) 888 // capacity of array is constant 889 default: 890 panic(fmt.Sprintf("Unhandled cap type: %T\n", argType)) 891 } 892 case "panic": 893 return c.formatExpr("$panic(%s)", c.translateImplicitConversion(args[0], types.NewInterface(nil, nil))) 894 case "append": 895 if ellipsis || len(args) == 1 { 896 argStr := c.translateArgs(sig, args, ellipsis) 897 return c.formatExpr("$appendSlice(%s, %s)", argStr[0], argStr[1]) 898 } 899 sliceType := sig.Results().At(0).Type().Underlying().(*types.Slice) 900 return c.formatExpr("$append(%e, %s)", args[0], strings.Join(c.translateExprSlice(args[1:], sliceType.Elem()), ", ")) 901 case "delete": 902 keyType := c.p.TypeOf(args[0]).Underlying().(*types.Map).Key() 903 return c.formatExpr(`delete %e[%s.keyFor(%s)]`, args[0], c.typeName(keyType), c.translateImplicitConversion(args[1], keyType)) 904 case "copy": 905 if basic, isBasic := c.p.TypeOf(args[1]).Underlying().(*types.Basic); isBasic && isString(basic) { 906 return c.formatExpr("$copyString(%e, %e)", args[0], args[1]) 907 } 908 return c.formatExpr("$copySlice(%e, %e)", args[0], args[1]) 909 case "print", "println": 910 return c.formatExpr("console.log(%s)", strings.Join(c.translateExprSlice(args, nil), ", ")) 911 case "complex": 912 argStr := c.translateArgs(sig, args, ellipsis) 913 return c.formatExpr("new %s(%s, %s)", c.typeName(sig.Results().At(0).Type()), argStr[0], argStr[1]) 914 case "real": 915 return c.formatExpr("%e.$real", args[0]) 916 case "imag": 917 return c.formatExpr("%e.$imag", args[0]) 918 case "recover": 919 return c.formatExpr("$recover()") 920 case "close": 921 return c.formatExpr(`$close(%e)`, args[0]) 922 default: 923 panic(fmt.Sprintf("Unhandled builtin: %s\n", name)) 924 } 925 } 926 927 func (c *funcContext) identifierConstant(expr ast.Expr) (string, bool) { 928 val := c.p.Types[expr].Value 929 if val == nil { 930 return "", false 931 } 932 s := constant.StringVal(val) 933 if len(s) == 0 { 934 return "", false 935 } 936 for i, c := range s { 937 if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (i > 0 && c >= '0' && c <= '9') || c == '_' || c == '$') { 938 return "", false 939 } 940 } 941 return s, true 942 } 943 944 func (c *funcContext) translateExprSlice(exprs []ast.Expr, desiredType types.Type) []string { 945 parts := make([]string, len(exprs)) 946 for i, expr := range exprs { 947 parts[i] = c.translateImplicitConversion(expr, desiredType).String() 948 } 949 return parts 950 } 951 952 func (c *funcContext) translateConversion(expr ast.Expr, desiredType types.Type) *expression { 953 exprType := c.p.TypeOf(expr) 954 if types.Identical(exprType, desiredType) { 955 return c.translateExpr(expr) 956 } 957 958 pkgPath := c.p.Pkg.Path() 959 if pkgPath == "reflect" || pkgPath == "internal/reflectlite" { 960 if call, isCall := expr.(*ast.CallExpr); isCall && types.Identical(c.p.TypeOf(call.Fun), types.Typ[types.UnsafePointer]) { 961 if ptr, isPtr := desiredType.(*types.Pointer); isPtr { 962 if named, isNamed := ptr.Elem().(*types.Named); isNamed { 963 switch named.Obj().Name() { 964 case "arrayType", "chanType", "funcType", "interfaceType", "mapType", "ptrType", "sliceType", "structType": 965 return c.formatExpr("%e.kindType", call.Args[0]) // unsafe conversion 966 default: 967 return c.translateExpr(expr) 968 } 969 } 970 } 971 } 972 } 973 974 switch t := desiredType.Underlying().(type) { 975 case *types.Basic: 976 switch { 977 case isInteger(t): 978 basicExprType := exprType.Underlying().(*types.Basic) 979 switch { 980 case is64Bit(t): 981 if !is64Bit(basicExprType) { 982 if basicExprType.Kind() == types.Uintptr { // this might be an Object returned from reflect.Value.Pointer() 983 return c.formatExpr("new %1s(0, %2e.constructor === Number ? %2e : 1)", c.typeName(desiredType), expr) 984 } 985 return c.formatExpr("new %s(0, %e)", c.typeName(desiredType), expr) 986 } 987 return c.formatExpr("new %1s(%2h, %2l)", c.typeName(desiredType), expr) 988 case is64Bit(basicExprType): 989 if !isUnsigned(t) && !isUnsigned(basicExprType) { 990 return c.fixNumber(c.formatParenExpr("%1l + ((%1h >> 31) * 4294967296)", expr), t) 991 } 992 return c.fixNumber(c.formatExpr("%s.$low", c.translateExpr(expr)), t) 993 case isFloat(basicExprType): 994 return c.formatParenExpr("%e >> 0", expr) 995 case types.Identical(exprType, types.Typ[types.UnsafePointer]): 996 return c.translateExpr(expr) 997 default: 998 return c.fixNumber(c.translateExpr(expr), t) 999 } 1000 case isFloat(t): 1001 if t.Kind() == types.Float32 && exprType.Underlying().(*types.Basic).Kind() == types.Float64 { 1002 return c.formatExpr("$fround(%e)", expr) 1003 } 1004 return c.formatExpr("%f", expr) 1005 case isComplex(t): 1006 return c.formatExpr("new %1s(%2r, %2i)", c.typeName(desiredType), expr) 1007 case isString(t): 1008 value := c.translateExpr(expr) 1009 switch et := exprType.Underlying().(type) { 1010 case *types.Basic: 1011 if is64Bit(et) { 1012 value = c.formatExpr("%s.$low", value) 1013 } 1014 if isNumeric(et) { 1015 return c.formatExpr("$encodeRune(%s)", value) 1016 } 1017 return value 1018 case *types.Slice: 1019 if types.Identical(et.Elem().Underlying(), types.Typ[types.Rune]) { 1020 return c.formatExpr("$runesToString(%s)", value) 1021 } 1022 return c.formatExpr("$bytesToString(%s)", value) 1023 default: 1024 panic(fmt.Sprintf("Unhandled conversion: %v\n", et)) 1025 } 1026 case t.Kind() == types.UnsafePointer: 1027 if unary, isUnary := expr.(*ast.UnaryExpr); isUnary && unary.Op == token.AND { 1028 if indexExpr, isIndexExpr := unary.X.(*ast.IndexExpr); isIndexExpr { 1029 return c.formatExpr("$sliceToArray(%s)", c.translateConversionToSlice(indexExpr.X, types.NewSlice(types.Typ[types.Uint8]))) 1030 } 1031 if ident, isIdent := unary.X.(*ast.Ident); isIdent && ident.Name == "_zero" { 1032 return c.formatExpr("new Uint8Array(0)") 1033 } 1034 } 1035 if ptr, isPtr := c.p.TypeOf(expr).(*types.Pointer); c.p.Pkg.Path() == "syscall" && isPtr { 1036 if s, isStruct := ptr.Elem().Underlying().(*types.Struct); isStruct { 1037 array := c.newVariable("_array") 1038 target := c.newVariable("_struct") 1039 c.Printf("%s = new Uint8Array(%d);", array, sizes32.Sizeof(s)) 1040 c.Delayed(func() { 1041 c.Printf("%s = %s, %s;", target, c.translateExpr(expr), c.loadStruct(array, target, s)) 1042 }) 1043 return c.formatExpr("%s", array) 1044 } 1045 } 1046 if call, ok := expr.(*ast.CallExpr); ok { 1047 if id, ok := call.Fun.(*ast.Ident); ok && id.Name == "new" { 1048 return c.formatExpr("new Uint8Array(%d)", int(sizes32.Sizeof(c.p.TypeOf(call.Args[0])))) 1049 } 1050 } 1051 } 1052 1053 case *types.Slice: 1054 switch et := exprType.Underlying().(type) { 1055 case *types.Basic: 1056 if isString(et) { 1057 if types.Identical(t.Elem().Underlying(), types.Typ[types.Rune]) { 1058 return c.formatExpr("new %s($stringToRunes(%e))", c.typeName(desiredType), expr) 1059 } 1060 return c.formatExpr("new %s($stringToBytes(%e))", c.typeName(desiredType), expr) 1061 } 1062 case *types.Array, *types.Pointer: 1063 return c.formatExpr("new %s(%e)", c.typeName(desiredType), expr) 1064 } 1065 1066 case *types.Pointer: 1067 switch u := t.Elem().Underlying().(type) { 1068 case *types.Array: 1069 return c.translateExpr(expr) 1070 case *types.Struct: 1071 if c.p.Pkg.Path() == "syscall" && types.Identical(exprType, types.Typ[types.UnsafePointer]) { 1072 array := c.newVariable("_array") 1073 target := c.newVariable("_struct") 1074 return c.formatExpr("(%s = %e, %s = %e, %s, %s)", array, expr, target, c.zeroValue(t.Elem()), c.loadStruct(array, target, u), target) 1075 } 1076 return c.formatExpr("$pointerOfStructConversion(%e, %s)", expr, c.typeName(t)) 1077 } 1078 1079 if !types.Identical(exprType, types.Typ[types.UnsafePointer]) { 1080 exprTypeElem := exprType.Underlying().(*types.Pointer).Elem() 1081 ptrVar := c.newVariable("_ptr") 1082 getterConv := c.translateConversion(c.setType(&ast.StarExpr{X: c.newIdent(ptrVar, exprType)}, exprTypeElem), t.Elem()) 1083 setterConv := c.translateConversion(c.newIdent("$v", t.Elem()), exprTypeElem) 1084 return c.formatExpr("(%1s = %2e, new %3s(function() { return %4s; }, function($v) { %1s.$set(%5s); }, %1s.$target))", ptrVar, expr, c.typeName(desiredType), getterConv, setterConv) 1085 } 1086 1087 case *types.Interface: 1088 if types.Identical(exprType, types.Typ[types.UnsafePointer]) { 1089 return c.translateExpr(expr) 1090 } 1091 } 1092 1093 return c.translateImplicitConversionWithCloning(expr, desiredType) 1094 } 1095 1096 func (c *funcContext) translateImplicitConversionWithCloning(expr ast.Expr, desiredType types.Type) *expression { 1097 switch desiredType.Underlying().(type) { 1098 case *types.Struct, *types.Array: 1099 switch expr.(type) { 1100 case nil, *ast.CompositeLit: 1101 // nothing 1102 default: 1103 return c.formatExpr("$clone(%e, %s)", expr, c.typeName(desiredType)) 1104 } 1105 } 1106 1107 return c.translateImplicitConversion(expr, desiredType) 1108 } 1109 1110 func (c *funcContext) translateImplicitConversion(expr ast.Expr, desiredType types.Type) *expression { 1111 if desiredType == nil { 1112 return c.translateExpr(expr) 1113 } 1114 1115 exprType := c.p.TypeOf(expr) 1116 if types.Identical(exprType, desiredType) { 1117 return c.translateExpr(expr) 1118 } 1119 1120 basicExprType, isBasicExpr := exprType.Underlying().(*types.Basic) 1121 if isBasicExpr && basicExprType.Kind() == types.UntypedNil { 1122 return c.formatExpr("%e", c.zeroValue(desiredType)) 1123 } 1124 1125 switch desiredType.Underlying().(type) { 1126 case *types.Slice: 1127 return c.formatExpr("$subslice(new %1s(%2e.$array), %2e.$offset, %2e.$offset + %2e.$length)", c.typeName(desiredType), expr) 1128 1129 case *types.Interface: 1130 if typesutil.IsJsObject(exprType) { 1131 // wrap JS object into js.Object struct when converting to interface 1132 return c.formatExpr("new $jsObjectPtr(%e)", expr) 1133 } 1134 if isWrapped(exprType) { 1135 return c.formatExpr("new %s(%e)", c.typeName(exprType), expr) 1136 } 1137 if _, isStruct := exprType.Underlying().(*types.Struct); isStruct { 1138 return c.formatExpr("new %1e.constructor.elem(%1e)", expr) 1139 } 1140 } 1141 1142 return c.translateExpr(expr) 1143 } 1144 1145 func (c *funcContext) translateConversionToSlice(expr ast.Expr, desiredType types.Type) *expression { 1146 switch c.p.TypeOf(expr).Underlying().(type) { 1147 case *types.Array, *types.Pointer: 1148 return c.formatExpr("new %s(%e)", c.typeName(desiredType), expr) 1149 } 1150 return c.translateExpr(expr) 1151 } 1152 1153 func (c *funcContext) loadStruct(array, target string, s *types.Struct) string { 1154 view := c.newVariable("_view") 1155 code := fmt.Sprintf("%s = new DataView(%s.buffer, %s.byteOffset)", view, array, array) 1156 var fields []*types.Var 1157 var collectFields func(s *types.Struct, path string) 1158 collectFields = func(s *types.Struct, path string) { 1159 for i := 0; i < s.NumFields(); i++ { 1160 field := s.Field(i) 1161 if fs, isStruct := field.Type().Underlying().(*types.Struct); isStruct { 1162 collectFields(fs, path+"."+fieldName(s, i)) 1163 continue 1164 } 1165 fields = append(fields, types.NewVar(0, nil, path+"."+fieldName(s, i), field.Type())) 1166 } 1167 } 1168 collectFields(s, target) 1169 offsets := sizes32.Offsetsof(fields) 1170 for i, field := range fields { 1171 switch t := field.Type().Underlying().(type) { 1172 case *types.Basic: 1173 if isNumeric(t) { 1174 if is64Bit(t) { 1175 code += fmt.Sprintf(", %s = new %s(%s.getUint32(%d, true), %s.getUint32(%d, true))", field.Name(), c.typeName(field.Type()), view, offsets[i]+4, view, offsets[i]) 1176 break 1177 } 1178 code += fmt.Sprintf(", %s = %s.get%s(%d, true)", field.Name(), view, toJavaScriptType(t), offsets[i]) 1179 } 1180 case *types.Array: 1181 code += fmt.Sprintf(`, %s = new ($nativeArray(%s))(%s.buffer, $min(%s.byteOffset + %d, %s.buffer.byteLength))`, field.Name(), typeKind(t.Elem()), array, array, offsets[i], array) 1182 } 1183 } 1184 return code 1185 } 1186 1187 func (c *funcContext) fixNumber(value *expression, basic *types.Basic) *expression { 1188 switch basic.Kind() { 1189 case types.Int8: 1190 return c.formatParenExpr("%s << 24 >> 24", value) 1191 case types.Uint8: 1192 return c.formatParenExpr("%s << 24 >>> 24", value) 1193 case types.Int16: 1194 return c.formatParenExpr("%s << 16 >> 16", value) 1195 case types.Uint16: 1196 return c.formatParenExpr("%s << 16 >>> 16", value) 1197 case types.Int32, types.Int, types.UntypedInt: 1198 return c.formatParenExpr("%s >> 0", value) 1199 case types.Uint32, types.Uint, types.Uintptr: 1200 return c.formatParenExpr("%s >>> 0", value) 1201 case types.Float32: 1202 return c.formatExpr("$fround(%s)", value) 1203 case types.Float64: 1204 return value 1205 default: 1206 panic(fmt.Sprintf("fixNumber: unhandled basic.Kind(): %s", basic.String())) 1207 } 1208 } 1209 1210 func (c *funcContext) internalize(s *expression, t types.Type) *expression { 1211 if typesutil.IsJsObject(t) { 1212 return s 1213 } 1214 switch u := t.Underlying().(type) { 1215 case *types.Basic: 1216 switch { 1217 case isBoolean(u): 1218 return c.formatExpr("!!(%s)", s) 1219 case isInteger(u) && !is64Bit(u): 1220 return c.fixNumber(c.formatExpr("$parseInt(%s)", s), u) 1221 case isFloat(u): 1222 return c.formatExpr("$parseFloat(%s)", s) 1223 } 1224 } 1225 return c.formatExpr("$internalize(%s, %s)", s, c.typeName(t)) 1226 } 1227 1228 func (c *funcContext) formatExpr(format string, a ...interface{}) *expression { 1229 return c.formatExprInternal(format, a, false) 1230 } 1231 1232 func (c *funcContext) formatParenExpr(format string, a ...interface{}) *expression { 1233 return c.formatExprInternal(format, a, true) 1234 } 1235 1236 func (c *funcContext) formatExprInternal(format string, a []interface{}, parens bool) *expression { 1237 processFormat := func(f func(uint8, uint8, int)) { 1238 n := 0 1239 for i := 0; i < len(format); i++ { 1240 b := format[i] 1241 if b == '%' { 1242 i++ 1243 k := format[i] 1244 if k >= '0' && k <= '9' { 1245 n = int(k - '0' - 1) 1246 i++ 1247 k = format[i] 1248 } 1249 f(0, k, n) 1250 n++ 1251 continue 1252 } 1253 f(b, 0, 0) 1254 } 1255 } 1256 1257 counts := make([]int, len(a)) 1258 processFormat(func(b, k uint8, n int) { 1259 switch k { 1260 case 'e', 'f', 'h', 'l', 'r', 'i': 1261 counts[n]++ 1262 } 1263 }) 1264 1265 out := bytes.NewBuffer(nil) 1266 vars := make([]string, len(a)) 1267 hasAssignments := false 1268 for i, e := range a { 1269 if counts[i] <= 1 { 1270 continue 1271 } 1272 if _, isIdent := e.(*ast.Ident); isIdent { 1273 continue 1274 } 1275 if val := c.p.Types[e.(ast.Expr)].Value; val != nil { 1276 continue 1277 } 1278 if !hasAssignments { 1279 hasAssignments = true 1280 out.WriteByte('(') 1281 parens = false 1282 } 1283 v := c.newVariable("x") 1284 out.WriteString(v + " = " + c.translateExpr(e.(ast.Expr)).String() + ", ") 1285 vars[i] = v 1286 } 1287 1288 processFormat(func(b, k uint8, n int) { 1289 writeExpr := func(suffix string) { 1290 if vars[n] != "" { 1291 out.WriteString(vars[n] + suffix) 1292 return 1293 } 1294 out.WriteString(c.translateExpr(a[n].(ast.Expr)).StringWithParens() + suffix) 1295 } 1296 switch k { 1297 case 0: 1298 out.WriteByte(b) 1299 case 's': 1300 if e, ok := a[n].(*expression); ok { 1301 out.WriteString(e.StringWithParens()) 1302 return 1303 } 1304 out.WriteString(a[n].(string)) 1305 case 'd': 1306 out.WriteString(strconv.Itoa(a[n].(int))) 1307 case 't': 1308 out.WriteString(a[n].(token.Token).String()) 1309 case 'e': 1310 e := a[n].(ast.Expr) 1311 if val := c.p.Types[e].Value; val != nil { 1312 out.WriteString(c.translateExpr(e).String()) 1313 return 1314 } 1315 writeExpr("") 1316 case 'f': 1317 e := a[n].(ast.Expr) 1318 if val := c.p.Types[e].Value; val != nil { 1319 d, _ := constant.Int64Val(constant.ToInt(val)) 1320 out.WriteString(strconv.FormatInt(d, 10)) 1321 return 1322 } 1323 if is64Bit(c.p.TypeOf(e).Underlying().(*types.Basic)) { 1324 out.WriteString("$flatten64(") 1325 writeExpr("") 1326 out.WriteString(")") 1327 return 1328 } 1329 writeExpr("") 1330 case 'h': 1331 e := a[n].(ast.Expr) 1332 if val := c.p.Types[e].Value; val != nil { 1333 d, _ := constant.Uint64Val(constant.ToInt(val)) 1334 if c.p.TypeOf(e).Underlying().(*types.Basic).Kind() == types.Int64 { 1335 out.WriteString(strconv.FormatInt(int64(d)>>32, 10)) 1336 return 1337 } 1338 out.WriteString(strconv.FormatUint(d>>32, 10)) 1339 return 1340 } 1341 writeExpr(".$high") 1342 case 'l': 1343 if val := c.p.Types[a[n].(ast.Expr)].Value; val != nil { 1344 d, _ := constant.Uint64Val(constant.ToInt(val)) 1345 out.WriteString(strconv.FormatUint(d&(1<<32-1), 10)) 1346 return 1347 } 1348 writeExpr(".$low") 1349 case 'r': 1350 if val := c.p.Types[a[n].(ast.Expr)].Value; val != nil { 1351 r, _ := constant.Float64Val(constant.Real(val)) 1352 out.WriteString(strconv.FormatFloat(r, 'g', -1, 64)) 1353 return 1354 } 1355 writeExpr(".$real") 1356 case 'i': 1357 if val := c.p.Types[a[n].(ast.Expr)].Value; val != nil { 1358 i, _ := constant.Float64Val(constant.Imag(val)) 1359 out.WriteString(strconv.FormatFloat(i, 'g', -1, 64)) 1360 return 1361 } 1362 writeExpr(".$imag") 1363 case '%': 1364 out.WriteRune('%') 1365 default: 1366 panic(fmt.Sprintf("formatExpr: %%%c%d", k, n)) 1367 } 1368 }) 1369 1370 if hasAssignments { 1371 out.WriteByte(')') 1372 } 1373 return &expression{str: out.String(), parens: parens} 1374 }