@@ -187,6 +187,23 @@ func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTag
187
187
return & PackageData {Package : pkg , JSFiles : jsFiles }, nil
188
188
}
189
189
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
+
190
207
// parseAndAugment parses and returns all .go files of given pkg.
191
208
// Standard Go library packages are augmented with files in compiler/natives folder.
192
209
// 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
195
212
// The native packages are augmented by the contents of natives.FS in the following way.
196
213
// The file names do not matter except the usual `_test` suffix. The files for
197
214
// 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.
201
221
func parseAndAugment (pkg * build.Package , isTest bool , fileSet * token.FileSet ) ([]* ast.File , error ) {
202
222
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 )
204
228
funcName := func (d * ast.FuncDecl ) string {
205
229
if d .Recv == nil || len (d .Recv .List ) == 0 {
206
230
return d .Name .Name
@@ -279,17 +303,17 @@ func parseAndAugment(pkg *build.Package, isTest bool, fileSet *token.FileSet) ([
279
303
for _ , decl := range file .Decls {
280
304
switch d := decl .(type ) {
281
305
case * ast.FuncDecl :
282
- replacedDeclNames [funcName (d )] = true
306
+ replacedDeclNames [funcName (d )] = overrideInfo { keepOverriden : findKeepOverridenComment ( d . Doc )}
283
307
case * ast.GenDecl :
284
308
switch d .Tok {
285
309
case token .TYPE :
286
310
for _ , spec := range d .Specs {
287
- replacedDeclNames [spec .(* ast.TypeSpec ).Name .Name ] = true
311
+ replacedDeclNames [spec .(* ast.TypeSpec ).Name .Name ] = overrideInfo {}
288
312
}
289
313
case token .VAR , token .CONST :
290
314
for _ , spec := range d .Specs {
291
315
for _ , name := range spec .(* ast.ValueSpec ).Names {
292
- replacedDeclNames [name .Name ] = true
316
+ replacedDeclNames [name .Name ] = overrideInfo {}
293
317
}
294
318
}
295
319
}
@@ -341,23 +365,30 @@ func parseAndAugment(pkg *build.Package, isTest bool, fileSet *token.FileSet) ([
341
365
for _ , decl := range file .Decls {
342
366
switch d := decl .(type ) {
343
367
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
+ }
346
377
}
347
378
case * ast.GenDecl :
348
379
switch d .Tok {
349
380
case token .TYPE :
350
381
for _ , spec := range d .Specs {
351
382
s := spec .(* ast.TypeSpec )
352
- if replacedDeclNames [s .Name .Name ] {
383
+ if _ , ok := replacedDeclNames [s .Name .Name ]; ok {
353
384
s .Name = ast .NewIdent ("_" )
354
385
}
355
386
}
356
387
case token .VAR , token .CONST :
357
388
for _ , spec := range d .Specs {
358
389
s := spec .(* ast.ValueSpec )
359
390
for i , name := range s .Names {
360
- if replacedDeclNames [name .Name ] {
391
+ if _ , ok := replacedDeclNames [name .Name ]; ok {
361
392
s .Names [i ] = ast .NewIdent ("_" )
362
393
}
363
394
}
0 commit comments