Skip to content

Commit c47ddde

Browse files
r-l-xflimzy
authored andcommitted
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 c409cd9 commit c47ddde

File tree

1 file changed

+41
-11
lines changed

1 file changed

+41
-11
lines changed

build/build.go

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,23 @@ func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTag
117117
return pkg, nil
118118
}
119119

120+
// Test if we find the '//gopherjs:keep_overridden' comment
121+
func findKeepOverridenComment(doc *ast.CommentGroup) bool {
122+
if doc == nil {
123+
return false
124+
}
125+
for _, comment := range doc.List {
126+
text := comment.Text
127+
if i := strings.Index(text, " "); i >= 0 {
128+
text = text[:i]
129+
}
130+
if text == "//gopherjs:keep_overridden" {
131+
return true
132+
}
133+
}
134+
return false
135+
}
136+
120137
// parseAndAugment parses and returns all .go files of given pkg.
121138
// Standard Go library packages are augmented with files in compiler/natives folder.
122139
// If isTest is true and pkg.ImportPath has no _test suffix, package is built for running internal tests.
@@ -125,12 +142,19 @@ func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTag
125142
// The native packages are augmented by the contents of natives.FS in the following way.
126143
// The file names do not matter except the usual `_test` suffix. The files for
127144
// native overrides get added to the package (even if they have the same name
128-
// as an existing file from the standard library). For all identifiers that exist
129-
// in the original AND the overrides, the original identifier in the AST gets
130-
// replaced by `_`. New identifiers that don't exist in original package get added.
145+
// as an existing file from the standard library). For function identifiers that exist
146+
// in the original AND the overrides AND that include the following directive in their comment:
147+
// //gopherjs:keep_overridden, the original identifier in the AST gets prefixed by
148+
// `_gopherjs_overridden_`. For other identifiers that exist in the original AND the overrides,
149+
// the original identifier gets replaced by `_`. New identifiers that don't exist in original
150+
// package get added.
131151
func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *token.FileSet) ([]*ast.File, []JSFile, error) {
132152
var files []*ast.File
133-
replacedDeclNames := make(map[string]bool)
153+
154+
type overrideInfo struct {
155+
keepOverriden bool
156+
}
157+
replacedDeclNames := make(map[string]overrideInfo)
134158
pruneOriginalFuncs := make(map[string]bool)
135159

136160
isXTest := strings.HasSuffix(pkg.ImportPath, "_test")
@@ -170,18 +194,18 @@ func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *toke
170194
switch d := decl.(type) {
171195
case *ast.FuncDecl:
172196
k := astutil.FuncKey(d)
173-
replacedDeclNames[k] = true
197+
replacedDeclNames[k] = overrideInfo{keepOverriden: findKeepOverridenComment(d.Doc)}
174198
pruneOriginalFuncs[k] = astutil.PruneOriginal(d)
175199
case *ast.GenDecl:
176200
switch d.Tok {
177201
case token.TYPE:
178202
for _, spec := range d.Specs {
179-
replacedDeclNames[spec.(*ast.TypeSpec).Name.Name] = true
203+
replacedDeclNames[spec.(*ast.TypeSpec).Name.Name] = overrideInfo{}
180204
}
181205
case token.VAR, token.CONST:
182206
for _, spec := range d.Specs {
183207
for _, name := range spec.(*ast.ValueSpec).Names {
184-
replacedDeclNames[name.Name] = true
208+
replacedDeclNames[name.Name] = overrideInfo{}
185209
}
186210
}
187211
}
@@ -234,20 +258,26 @@ func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *toke
234258
switch d := decl.(type) {
235259
case *ast.FuncDecl:
236260
k := astutil.FuncKey(d)
237-
if replacedDeclNames[k] {
238-
d.Name = ast.NewIdent("_")
261+
if info, ok := replacedDeclNames[k]; ok {
239262
if pruneOriginalFuncs[k] {
240263
// Prune function bodies, since it may contain code invalid for
241264
// GopherJS and pin unwanted imports.
242265
d.Body = nil
243266
}
267+
if info.keepOverriden {
268+
// Allow overridden function calls
269+
// The standard library implementation of foo() becomes _gopherjs_overridden_foo()
270+
d.Name.Name = "_gopherjs_overridden_" + d.Name.Name
271+
} else {
272+
d.Name = ast.NewIdent("_")
273+
}
244274
}
245275
case *ast.GenDecl:
246276
switch d.Tok {
247277
case token.TYPE:
248278
for _, spec := range d.Specs {
249279
s := spec.(*ast.TypeSpec)
250-
if replacedDeclNames[s.Name.Name] {
280+
if _, ok := replacedDeclNames[s.Name.Name]; ok {
251281
s.Name = ast.NewIdent("_")
252282
s.Type = &ast.StructType{Struct: s.Pos(), Fields: &ast.FieldList{}}
253283
s.TypeParams = nil
@@ -257,7 +287,7 @@ func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *toke
257287
for _, spec := range d.Specs {
258288
s := spec.(*ast.ValueSpec)
259289
for i, name := range s.Names {
260-
if replacedDeclNames[name.Name] {
290+
if _, ok := replacedDeclNames[name.Name]; ok {
261291
s.Names[i] = ast.NewIdent("_")
262292
}
263293
}

0 commit comments

Comments
 (0)