Skip to content

Commit 038d281

Browse files
committed
Rename and document functions responsible for identifier generation.
These functions provide mappings from Go entities (variables, types, functions, etc.) to JS identifiers assigned to them. This commit adds documentation comments and renames a couple of methods to better match their role. (based on commit 4767913)
1 parent 606129e commit 038d281

File tree

4 files changed

+70
-46
lines changed

4 files changed

+70
-46
lines changed

compiler/expressions.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -398,14 +398,14 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
398398
if isUnsigned(basic) {
399399
shift = ">>>"
400400
}
401-
return fc.formatExpr(`(%1s = %2e / %3e, (%1s === %1s && %1s !== 1/0 && %1s !== -1/0) ? %1s %4s 0 : $throwRuntimeError("integer divide by zero"))`, fc.newVariable("_q"), e.X, e.Y, shift)
401+
return fc.formatExpr(`(%1s = %2e / %3e, (%1s === %1s && %1s !== 1/0 && %1s !== -1/0) ? %1s %4s 0 : $throwRuntimeError("integer divide by zero"))`, fc.newLocalVariable("_q"), e.X, e.Y, shift)
402402
}
403403
if basic.Kind() == types.Float32 {
404404
return fc.fixNumber(fc.formatExpr("%e / %e", e.X, e.Y), basic)
405405
}
406406
return fc.formatExpr("%e / %e", e.X, e.Y)
407407
case token.REM:
408-
return fc.formatExpr(`(%1s = %2e %% %3e, %1s === %1s ? %1s : $throwRuntimeError("integer divide by zero"))`, fc.newVariable("_r"), e.X, e.Y)
408+
return fc.formatExpr(`(%1s = %2e %% %3e, %1s === %1s ? %1s : $throwRuntimeError("integer divide by zero"))`, fc.newLocalVariable("_r"), e.X, e.Y)
409409
case token.SHL, token.SHR:
410410
op := e.Op.String()
411411
if e.Op == token.SHR && isUnsigned(basic) {
@@ -421,7 +421,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
421421
if e.Op == token.SHR && !isUnsigned(basic) {
422422
return fc.fixNumber(fc.formatParenExpr("%e >> $min(%f, 31)", e.X, e.Y), basic)
423423
}
424-
y := fc.newVariable("y")
424+
y := fc.newLocalVariable("y")
425425
return fc.fixNumber(fc.formatExpr("(%s = %f, %s < 32 ? (%e %s %s) : 0)", y, e.Y, y, e.X, op, y), basic)
426426
case token.AND, token.OR:
427427
if isUnsigned(basic) {
@@ -444,7 +444,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
444444
if fc.Blocking[e.Y] {
445445
skipCase := fc.caseCounter
446446
fc.caseCounter++
447-
resultVar := fc.newVariable("_v")
447+
resultVar := fc.newLocalVariable("_v")
448448
fc.Printf("if (!(%s)) { %s = false; $s = %d; continue s; }", fc.translateExpr(e.X), resultVar, skipCase)
449449
fc.Printf("%s = %s; case %d:", resultVar, fc.translateExpr(e.Y), skipCase)
450450
return fc.formatExpr("%s", resultVar)
@@ -454,7 +454,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
454454
if fc.Blocking[e.Y] {
455455
skipCase := fc.caseCounter
456456
fc.caseCounter++
457-
resultVar := fc.newVariable("_v")
457+
resultVar := fc.newLocalVariable("_v")
458458
fc.Printf("if (%s) { %s = true; $s = %d; continue s; }", fc.translateExpr(e.X), resultVar, skipCase)
459459
fc.Printf("%s = %s; case %d:", resultVar, fc.translateExpr(e.Y), skipCase)
460460
return fc.formatExpr("%s", resultVar)
@@ -513,15 +513,15 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
513513
if _, isTuple := exprType.(*types.Tuple); isTuple {
514514
return fc.formatExpr(
515515
`(%1s = $mapIndex(%2e,%3s), %1s !== undefined ? [%1s.v, true] : [%4e, false])`,
516-
fc.newVariable("_entry"),
516+
fc.newLocalVariable("_entry"),
517517
e.X,
518518
key,
519519
fc.zeroValue(t.Elem()),
520520
)
521521
}
522522
return fc.formatExpr(
523523
`(%1s = $mapIndex(%2e,%3s), %1s !== undefined ? %1s.v : %4e)`,
524-
fc.newVariable("_entry"),
524+
fc.newLocalVariable("_entry"),
525525
e.X,
526526
key,
527527
fc.zeroValue(t.Elem()),
@@ -689,13 +689,13 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
689689
case "Call":
690690
if id, ok := fc.identifierConstant(e.Args[0]); ok {
691691
if e.Ellipsis.IsValid() {
692-
objVar := fc.newVariable("obj")
692+
objVar := fc.newLocalVariable("obj")
693693
return fc.formatExpr("(%s = %s, %s.%s.apply(%s, %s))", objVar, recv, objVar, id, objVar, externalizeExpr(e.Args[1]))
694694
}
695695
return fc.formatExpr("%s(%s)", globalRef(id), externalizeArgs(e.Args[1:]))
696696
}
697697
if e.Ellipsis.IsValid() {
698-
objVar := fc.newVariable("obj")
698+
objVar := fc.newLocalVariable("obj")
699699
return fc.formatExpr("(%s = %s, %s[$externalize(%e, $String)].apply(%s, %s))", objVar, recv, objVar, e.Args[0], objVar, externalizeExpr(e.Args[1]))
700700
}
701701
return fc.formatExpr("%s[$externalize(%e, $String)](%s)", recv, e.Args[0], externalizeArgs(e.Args[1:]))
@@ -842,7 +842,7 @@ func (fc *funcContext) translateCall(e *ast.CallExpr, sig *types.Signature, fun
842842
fc.caseCounter++
843843
returnVar := "$r"
844844
if sig.Results().Len() != 0 {
845-
returnVar = fc.newVariable("_r")
845+
returnVar = fc.newLocalVariable("_r")
846846
}
847847
fc.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)
848848
if sig.Results().Len() != 0 {
@@ -891,7 +891,7 @@ func (fc *funcContext) delegatedCall(expr *ast.CallExpr) (callable *expression,
891891
ellipsis := expr.Ellipsis
892892

893893
for i := range expr.Args {
894-
v := fc.newVariable("_arg")
894+
v := fc.newLocalVariable("_arg")
895895
vars[i] = v
896896
// Subtle: the proxy lambda argument needs to be assigned with the type
897897
// that the original function expects, and not with the argument
@@ -1172,8 +1172,8 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
11721172
}
11731173
if ptr, isPtr := fc.typeOf(expr).(*types.Pointer); fc.pkgCtx.Pkg.Path() == "syscall" && isPtr {
11741174
if s, isStruct := ptr.Elem().Underlying().(*types.Struct); isStruct {
1175-
array := fc.newVariable("_array")
1176-
target := fc.newVariable("_struct")
1175+
array := fc.newLocalVariable("_array")
1176+
target := fc.newLocalVariable("_struct")
11771177
fc.Printf("%s = new Uint8Array(%d);", array, sizes32.Sizeof(s))
11781178
fc.Delayed(func() {
11791179
fc.Printf("%s = %s, %s;", target, fc.translateExpr(expr), fc.loadStruct(array, target, s))
@@ -1221,8 +1221,8 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
12211221
// struct pointer when handling syscalls.
12221222
// TODO(nevkontakte): Add a runtime assertion that the unsafe.Pointer is
12231223
// indeed pointing at a byte array.
1224-
array := fc.newVariable("_array")
1225-
target := fc.newVariable("_struct")
1224+
array := fc.newLocalVariable("_array")
1225+
target := fc.newLocalVariable("_struct")
12261226
return fc.formatExpr("(%s = %e, %s = %e, %s, %s)", array, expr, target, fc.zeroValue(t.Elem()), fc.loadStruct(array, target, ptrElType), target)
12271227
}
12281228
// Convert between structs of different types but identical layouts,
@@ -1244,7 +1244,7 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
12441244
// type iPtr *int; var c int = 42; println((iPtr)(&c));
12451245
// TODO(nevkontakte): Are there any other cases that fall into this case?
12461246
exprTypeElem := exprType.Underlying().(*types.Pointer).Elem()
1247-
ptrVar := fc.newVariable("_ptr")
1247+
ptrVar := fc.newLocalVariable("_ptr")
12481248
getterConv := fc.translateConversion(fc.setType(&ast.StarExpr{X: fc.newIdent(ptrVar, exprType)}, exprTypeElem), t.Elem())
12491249
setterConv := fc.translateConversion(fc.newIdent("$v", t.Elem()), exprTypeElem)
12501250
return fc.formatExpr("(%1s = %2e, new %3s(function() { return %4s; }, function($v) { %1s.$set(%5s); }, %1s.$target))", ptrVar, expr, fc.typeName(desiredType), getterConv, setterConv)
@@ -1311,7 +1311,7 @@ func (fc *funcContext) translateConversionToSlice(expr ast.Expr, desiredType typ
13111311
}
13121312

13131313
func (fc *funcContext) loadStruct(array, target string, s *types.Struct) string {
1314-
view := fc.newVariable("_view")
1314+
view := fc.newLocalVariable("_view")
13151315
code := fmt.Sprintf("%s = new DataView(%s.buffer, %s.byteOffset)", view, array, array)
13161316
var fields []*types.Var
13171317
var collectFields func(s *types.Struct, path string)
@@ -1441,7 +1441,7 @@ func (fc *funcContext) formatExprInternal(format string, a []interface{}, parens
14411441
out.WriteByte('(')
14421442
parens = false
14431443
}
1444-
v := fc.newVariable("x")
1444+
v := fc.newLocalVariable("x")
14451445
out.WriteString(v + " = " + fc.translateExpr(e.(ast.Expr)).String() + ", ")
14461446
vars[i] = v
14471447
}

compiler/package.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ func Compile(importPath string, files []*ast.File, fileSet *token.FileSet, impor
297297
// but now we do it here to maintain previous behavior.
298298
continue
299299
}
300-
funcCtx.pkgCtx.pkgVars[importedPkg.Path()] = funcCtx.newVariableWithLevel(importedPkg.Name(), true)
300+
funcCtx.pkgCtx.pkgVars[importedPkg.Path()] = funcCtx.newVariable(importedPkg.Name(), true)
301301
importedPaths = append(importedPaths, importedPkg.Path())
302302
}
303303
sort.Strings(importedPaths)
@@ -832,12 +832,12 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
832832
var params []string
833833
for _, param := range typ.Params.List {
834834
if len(param.Names) == 0 {
835-
params = append(params, c.newVariable("param"))
835+
params = append(params, c.newLocalVariable("param"))
836836
continue
837837
}
838838
for _, ident := range param.Names {
839839
if isBlank(ident) {
840-
params = append(params, c.newVariable("param"))
840+
params = append(params, c.newLocalVariable("param"))
841841
continue
842842
}
843843
params = append(params, c.objectName(c.pkgCtx.Defs[ident]))

compiler/statements.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
125125
if s.Init != nil {
126126
fc.translateStmt(s.Init, nil)
127127
}
128-
refVar := fc.newVariable("_ref")
128+
refVar := fc.newLocalVariable("_ref")
129129
var expr ast.Expr
130130
switch a := s.Assign.(type) {
131131
case *ast.AssignStmt:
@@ -188,14 +188,14 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
188188
}, label, fc.Flattened[s])
189189

190190
case *ast.RangeStmt:
191-
refVar := fc.newVariable("_ref")
191+
refVar := fc.newLocalVariable("_ref")
192192
fc.Printf("%s = %s;", refVar, fc.translateExpr(s.X))
193193

194194
switch t := fc.typeOf(s.X).Underlying().(type) {
195195
case *types.Basic:
196-
iVar := fc.newVariable("_i")
196+
iVar := fc.newLocalVariable("_i")
197197
fc.Printf("%s = 0;", iVar)
198-
runeVar := fc.newVariable("_rune")
198+
runeVar := fc.newLocalVariable("_rune")
199199
fc.translateLoopingStmt(func() string { return iVar + " < " + refVar + ".length" }, s.Body, func() {
200200
fc.Printf("%s = $decodeRune(%s, %s);", runeVar, refVar, iVar)
201201
if !isBlank(s.Key) {
@@ -209,16 +209,16 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
209209
}, label, fc.Flattened[s])
210210

211211
case *types.Map:
212-
iVar := fc.newVariable("_i")
212+
iVar := fc.newLocalVariable("_i")
213213
fc.Printf("%s = 0;", iVar)
214-
keysVar := fc.newVariable("_keys")
214+
keysVar := fc.newLocalVariable("_keys")
215215
fc.Printf("%s = %s ? %s.keys() : undefined;", keysVar, refVar, refVar)
216216

217-
sizeVar := fc.newVariable("_size")
217+
sizeVar := fc.newLocalVariable("_size")
218218
fc.Printf("%s = %s ? %s.size : 0;", sizeVar, refVar, refVar)
219219
fc.translateLoopingStmt(func() string { return iVar + " < " + sizeVar }, s.Body, func() {
220-
keyVar := fc.newVariable("_key")
221-
entryVar := fc.newVariable("_entry")
220+
keyVar := fc.newLocalVariable("_key")
221+
entryVar := fc.newLocalVariable("_entry")
222222
fc.Printf("%s = %s.next().value;", keyVar, keysVar)
223223
fc.Printf("%s = %s.get(%s);", entryVar, refVar, keyVar)
224224
fc.translateStmt(&ast.IfStmt{
@@ -249,7 +249,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
249249
length = refVar + ".$length"
250250
elemType = t2.Elem()
251251
}
252-
iVar := fc.newVariable("_i")
252+
iVar := fc.newLocalVariable("_i")
253253
fc.Printf("%s = 0;", iVar)
254254
fc.translateLoopingStmt(func() string { return iVar + " < " + length }, s.Body, func() {
255255
if !isBlank(s.Key) {
@@ -266,7 +266,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
266266
}, label, fc.Flattened[s])
267267

268268
case *types.Chan:
269-
okVar := fc.newIdent(fc.newVariable("_ok"), types.Typ[types.Bool])
269+
okVar := fc.newIdent(fc.newLocalVariable("_ok"), types.Typ[types.Bool])
270270
key := s.Key
271271
tok := s.Tok
272272
if key == nil {
@@ -355,7 +355,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
355355
if rVal != "" {
356356
// If returned expression is non empty, evaluate and store it in a
357357
// variable to avoid double-execution in case a deferred function blocks.
358-
rVar := fc.newVariable("$r")
358+
rVar := fc.newLocalVariable("$r")
359359
fc.Printf("%s =%s;", rVar, rVal)
360360
rVal = " " + rVar
361361
}
@@ -387,7 +387,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
387387
fc.Printf("%s", fc.translateAssign(lhs, s.Rhs[0], s.Tok == token.DEFINE))
388388

389389
case len(s.Lhs) > 1 && len(s.Rhs) == 1:
390-
tupleVar := fc.newVariable("_tuple")
390+
tupleVar := fc.newLocalVariable("_tuple")
391391
fc.Printf("%s = %s;", tupleVar, fc.translateExpr(s.Rhs[0]))
392392
tuple := fc.typeOf(s.Rhs[0]).(*types.Tuple)
393393
for i, lhs := range s.Lhs {
@@ -399,7 +399,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
399399
case len(s.Lhs) == len(s.Rhs):
400400
tmpVars := make([]string, len(s.Rhs))
401401
for i, rhs := range s.Rhs {
402-
tmpVars[i] = fc.newVariable("_tmp")
402+
tmpVars[i] = fc.newLocalVariable("_tmp")
403403
if isBlank(astutil.RemoveParens(s.Lhs[i])) {
404404
fc.Printf("$unused(%s);", fc.translateExpr(rhs))
405405
continue
@@ -478,7 +478,7 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
478478
fc.translateStmt(&ast.ExprStmt{X: call}, label)
479479

480480
case *ast.SelectStmt:
481-
selectionVar := fc.newVariable("_selection")
481+
selectionVar := fc.newLocalVariable("_selection")
482482
var channels []string
483483
var caseClauses []*ast.CaseClause
484484
flattened := false
@@ -704,7 +704,7 @@ func (fc *funcContext) translateAssign(lhs, rhs ast.Expr, define bool) string {
704704
if typesutil.IsJsObject(fc.typeOf(l.Index)) {
705705
fc.pkgCtx.errList = append(fc.pkgCtx.errList, types.Error{Fset: fc.pkgCtx.fileSet, Pos: l.Index.Pos(), Msg: "cannot use js.Object as map key"})
706706
}
707-
keyVar := fc.newVariable("_key")
707+
keyVar := fc.newLocalVariable("_key")
708708
return fmt.Sprintf(
709709
`%s = %s; (%s || $throwRuntimeError("assignment to entry in nil map")).set(%s.keyFor(%s), { k: %s, v: %s });`,
710710
keyVar,
@@ -799,7 +799,7 @@ func (fc *funcContext) translateResults(results []ast.Expr) string {
799799
return " " + resultExpr
800800
}
801801

802-
tmpVar := fc.newVariable("_returncast")
802+
tmpVar := fc.newLocalVariable("_returncast")
803803
fc.Printf("%s = %s;", tmpVar, resultExpr)
804804

805805
// Not all the return types matched, map everything out for implicit casting

compiler/utils.go

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func (fc *funcContext) expandTupleArgs(argExprs []ast.Expr) []ast.Expr {
124124
return argExprs
125125
}
126126

127-
tupleVar := fc.newVariable("_tuple")
127+
tupleVar := fc.newLocalVariable("_tuple")
128128
fc.Printf("%s = %s;", tupleVar, fc.translateExpr(argExprs[0]))
129129
argExprs = make([]ast.Expr, tuple.Len())
130130
for i := range argExprs {
@@ -152,7 +152,7 @@ func (fc *funcContext) translateArgs(sig *types.Signature, argExprs []ast.Expr,
152152
arg := fc.translateImplicitConversionWithCloning(argExpr, sigTypes.Param(i, ellipsis)).String()
153153

154154
if preserveOrder && fc.pkgCtx.Types[argExpr].Value == nil {
155-
argVar := fc.newVariable("_arg")
155+
argVar := fc.newLocalVariable("_arg")
156156
fc.Printf("%s = %s;", argVar, arg)
157157
arg = argVar
158158
}
@@ -247,11 +247,26 @@ func (fc *funcContext) newConst(t types.Type, value constant.Value) ast.Expr {
247247
return id
248248
}
249249

250-
func (fc *funcContext) newVariable(name string) string {
251-
return fc.newVariableWithLevel(name, false)
250+
// newLocalVariable assigns a new JavaScript variable name for the given Go
251+
// local variable name. In this context "local" means "in scope of the current"
252+
// functionContext.
253+
func (fc *funcContext) newLocalVariable(name string) string {
254+
return fc.newVariable(name, false)
252255
}
253256

254-
func (fc *funcContext) newVariableWithLevel(name string, pkgLevel bool) string {
257+
// newVariable assigns a new JavaScript variable name for the given Go variable
258+
// or type.
259+
//
260+
// If there is already a variable with the same name visible in the current
261+
// function context (e.g. due to shadowing), the returned name will be suffixed
262+
// with a number to prevent conflict. This is necessary because Go name
263+
// resolution scopes differ from var declarations in JS.
264+
//
265+
// If pkgLevel is true, the variable is declared at the package level and added
266+
// to this functionContext, as well as all parents, but not to the list of local
267+
// variables. If false, it is added to this context only, as well as the list of
268+
// local vars.
269+
func (fc *funcContext) newVariable(name string, pkgLevel bool) string {
255270
if name == "" {
256271
panic("newVariable: empty name")
257272
}
@@ -373,7 +388,7 @@ func (fc *funcContext) objectName(o types.Object) string {
373388
name, ok := fc.assignedObjectName(o)
374389
if !ok {
375390
pkgLevel := isPkgLevel(o)
376-
name = fc.newVariableWithLevel(o.Name(), pkgLevel)
391+
name = fc.newVariable(o.Name(), pkgLevel)
377392
if pkgLevel {
378393
fc.root().objectNames[o] = name
379394
} else {
@@ -405,12 +420,17 @@ func (fc *funcContext) varPtrName(o *types.Var) string {
405420

406421
name, ok := fc.pkgCtx.varPtrNames[o]
407422
if !ok {
408-
name = fc.newVariableWithLevel(o.Name()+"$ptr", isPkgLevel(o))
423+
name = fc.newVariable(o.Name()+"$ptr", isPkgLevel(o))
409424
fc.pkgCtx.varPtrNames[o] = name
410425
}
411426
return name
412427
}
413428

429+
// typeName returns a JS identifier name for the given Go type.
430+
//
431+
// For the built-in types it returns identifiers declared in the prelude. For
432+
// all user-defined or composite types it creates a unique JS identifier and
433+
// will return it on all subsequent calls for the type.
414434
func (fc *funcContext) typeName(ty types.Type) string {
415435
switch t := ty.(type) {
416436
case *types.Basic:
@@ -430,10 +450,14 @@ func (fc *funcContext) typeName(ty types.Type) string {
430450
}
431451
}
432452

453+
// For anonymous composite types, generate a synthetic package-level type
454+
// declaration, which will be reused for all instances of this time. This
455+
// improves performance, since runtime won't have to synthesize the same type
456+
// repeatedly.
433457
anonType, ok := fc.pkgCtx.anonTypeMap.At(ty).(*types.TypeName)
434458
if !ok {
435459
fc.initArgs(ty) // cause all embedded types to be registered
436-
varName := fc.newVariableWithLevel(strings.ToLower(typeKind(ty)[5:])+"Type", true)
460+
varName := fc.newVariable(strings.ToLower(typeKind(ty)[5:])+"Type", true)
437461
anonType = types.NewTypeName(token.NoPos, fc.pkgCtx.Pkg, varName, ty) // fake types.TypeName
438462
fc.pkgCtx.anonTypes = append(fc.pkgCtx.anonTypes, anonType)
439463
fc.pkgCtx.anonTypeMap.Set(ty, anonType)

0 commit comments

Comments
 (0)