Skip to content

Commit 27a4b71

Browse files
committed
build: Allow overriden functions calls
Before this commit, every overriden standard library function was renamed '_'. Now, if there is the following directive in the function comment: "//gopherjs:keep_overridden", they are prefixed with "_gopherjs_overridden_" so that they can be called from the overriding function. This is typically useful to use the standard library implementation as a fallback.
1 parent 558a913 commit 27a4b71

File tree

1 file changed

+42
-11
lines changed

1 file changed

+42
-11
lines changed

build/build.go

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,23 @@ func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTag
187187
return &PackageData{Package: pkg, JSFiles: jsFiles}, nil
188188
}
189189

190+
// Test if we find the '//gopherjs:keep_overridden' comment
191+
func findKeepOverridenComment(doc *ast.CommentGroup) bool {
192+
if doc == nil {
193+
return false
194+
}
195+
for _, comment := range doc.List {
196+
text := comment.Text
197+
if i := strings.Index(text, " "); i >= 0 {
198+
text = text[:i]
199+
}
200+
if text == "//gopherjs:keep_overridden" {
201+
return true
202+
}
203+
}
204+
return false
205+
}
206+
190207
// parseAndAugment parses and returns all .go files of given pkg.
191208
// Standard Go library packages are augmented with files in compiler/natives folder.
192209
// If isTest is true and pkg.ImportPath has no _test suffix, package is built for running internal tests.
@@ -195,12 +212,19 @@ func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTag
195212
// The native packages are augmented by the contents of natives.FS in the following way.
196213
// The file names do not matter except the usual `_test` suffix. The files for
197214
// native overrides get added to the package (even if they have the same name
198-
// as an existing file from the standard library). For all identifiers that exist
199-
// in the original AND the overrides, the original identifier in the AST gets
200-
// replaced by `_`. New identifiers that don't exist in original package get added.
215+
// as an existing file from the standard library). For function identifiers that exist
216+
// in the original AND the overrides AND that include the following directive in their comment:
217+
// //gopherjs:keep_overridden, the original identifier in the AST gets prefixed by
218+
// `_gopherjs_overridden_`. For other identifiers that exist in the original AND the overrides,
219+
// the original identifier gets replaced by `_`. New identifiers that don't exist in original
220+
// package get added.
201221
func parseAndAugment(pkg *build.Package, isTest bool, fileSet *token.FileSet) ([]*ast.File, error) {
202222
var files []*ast.File
203-
replacedDeclNames := make(map[string]bool)
223+
224+
type overrideInfo struct {
225+
keepOverriden bool
226+
}
227+
replacedDeclNames := make(map[string]overrideInfo)
204228
funcName := func(d *ast.FuncDecl) string {
205229
if d.Recv == nil || len(d.Recv.List) == 0 {
206230
return d.Name.Name
@@ -279,17 +303,17 @@ func parseAndAugment(pkg *build.Package, isTest bool, fileSet *token.FileSet) ([
279303
for _, decl := range file.Decls {
280304
switch d := decl.(type) {
281305
case *ast.FuncDecl:
282-
replacedDeclNames[funcName(d)] = true
306+
replacedDeclNames[funcName(d)] = overrideInfo{keepOverriden: findKeepOverridenComment(d.Doc)}
283307
case *ast.GenDecl:
284308
switch d.Tok {
285309
case token.TYPE:
286310
for _, spec := range d.Specs {
287-
replacedDeclNames[spec.(*ast.TypeSpec).Name.Name] = true
311+
replacedDeclNames[spec.(*ast.TypeSpec).Name.Name] = overrideInfo{}
288312
}
289313
case token.VAR, token.CONST:
290314
for _, spec := range d.Specs {
291315
for _, name := range spec.(*ast.ValueSpec).Names {
292-
replacedDeclNames[name.Name] = true
316+
replacedDeclNames[name.Name] = overrideInfo{}
293317
}
294318
}
295319
}
@@ -341,23 +365,30 @@ func parseAndAugment(pkg *build.Package, isTest bool, fileSet *token.FileSet) ([
341365
for _, decl := range file.Decls {
342366
switch d := decl.(type) {
343367
case *ast.FuncDecl:
344-
if replacedDeclNames[funcName(d)] {
345-
d.Name = ast.NewIdent("_")
368+
if info, ok := replacedDeclNames[funcName(d)]; ok {
369+
if info.keepOverriden {
370+
// Allow overridden function calls
371+
// The standard library implementation of foo() becomes _gopherjs_overridden_foo()
372+
d.Name.Name = "_gopherjs_overridden_" + d.Name.Name
373+
println("overriding ", d.Name.Name)
374+
} else {
375+
d.Name = ast.NewIdent("_")
376+
}
346377
}
347378
case *ast.GenDecl:
348379
switch d.Tok {
349380
case token.TYPE:
350381
for _, spec := range d.Specs {
351382
s := spec.(*ast.TypeSpec)
352-
if replacedDeclNames[s.Name.Name] {
383+
if _, ok := replacedDeclNames[s.Name.Name]; ok {
353384
s.Name = ast.NewIdent("_")
354385
}
355386
}
356387
case token.VAR, token.CONST:
357388
for _, spec := range d.Specs {
358389
s := spec.(*ast.ValueSpec)
359390
for i, name := range s.Names {
360-
if replacedDeclNames[name.Name] {
391+
if _, ok := replacedDeclNames[name.Name]; ok {
361392
s.Names[i] = ast.NewIdent("_")
362393
}
363394
}

0 commit comments

Comments
 (0)