OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [go/] [ast/] [filter.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
package ast
6
 
7
import (
8
        "go/token"
9
        "sort"
10
)
11
 
12
// ----------------------------------------------------------------------------
13
// Export filtering
14
 
15
// exportFilter is a special filter function to extract exported nodes.
16
func exportFilter(name string) bool {
17
        return IsExported(name)
18
}
19
 
20
// FileExports trims the AST for a Go source file in place such that
21
// only exported nodes remain: all top-level identifiers which are not exported
22
// and their associated information (such as type, initial value, or function
23
// body) are removed. Non-exported fields and methods of exported types are
24
// stripped. The File.Comments list is not changed.
25
//
26
// FileExports returns true if there are exported declarations;
27
// it returns false otherwise.
28
//
29
func FileExports(src *File) bool {
30
        return filterFile(src, exportFilter, true)
31
}
32
 
33
// PackageExports trims the AST for a Go package in place such that
34
// only exported nodes remain. The pkg.Files list is not changed, so that
35
// file names and top-level package comments don't get lost.
36
//
37
// PackageExports returns true if there are exported declarations;
38
// it returns false otherwise.
39
//
40
func PackageExports(pkg *Package) bool {
41
        return filterPackage(pkg, exportFilter, true)
42
}
43
 
44
// ----------------------------------------------------------------------------
45
// General filtering
46
 
47
type Filter func(string) bool
48
 
49
func filterIdentList(list []*Ident, f Filter) []*Ident {
50
        j := 0
51
        for _, x := range list {
52
                if f(x.Name) {
53
                        list[j] = x
54
                        j++
55
                }
56
        }
57
        return list[0:j]
58
}
59
 
60
// fieldName assumes that x is the type of an anonymous field and
61
// returns the corresponding field name. If x is not an acceptable
62
// anonymous field, the result is nil.
63
//
64
func fieldName(x Expr) *Ident {
65
        switch t := x.(type) {
66
        case *Ident:
67
                return t
68
        case *SelectorExpr:
69
                if _, ok := t.X.(*Ident); ok {
70
                        return t.Sel
71
                }
72
        case *StarExpr:
73
                return fieldName(t.X)
74
        }
75
        return nil
76
}
77
 
78
func filterFieldList(fields *FieldList, filter Filter, export bool) (removedFields bool) {
79
        if fields == nil {
80
                return false
81
        }
82
        list := fields.List
83
        j := 0
84
        for _, f := range list {
85
                keepField := false
86
                if len(f.Names) == 0 {
87
                        // anonymous field
88
                        name := fieldName(f.Type)
89
                        keepField = name != nil && filter(name.Name)
90
                } else {
91
                        n := len(f.Names)
92
                        f.Names = filterIdentList(f.Names, filter)
93
                        if len(f.Names) < n {
94
                                removedFields = true
95
                        }
96
                        keepField = len(f.Names) > 0
97
                }
98
                if keepField {
99
                        if export {
100
                                filterType(f.Type, filter, export)
101
                        }
102
                        list[j] = f
103
                        j++
104
                }
105
        }
106
        if j < len(list) {
107
                removedFields = true
108
        }
109
        fields.List = list[0:j]
110
        return
111
}
112
 
113
func filterParamList(fields *FieldList, filter Filter, export bool) bool {
114
        if fields == nil {
115
                return false
116
        }
117
        var b bool
118
        for _, f := range fields.List {
119
                if filterType(f.Type, filter, export) {
120
                        b = true
121
                }
122
        }
123
        return b
124
}
125
 
126
func filterType(typ Expr, f Filter, export bool) bool {
127
        switch t := typ.(type) {
128
        case *Ident:
129
                return f(t.Name)
130
        case *ParenExpr:
131
                return filterType(t.X, f, export)
132
        case *ArrayType:
133
                return filterType(t.Elt, f, export)
134
        case *StructType:
135
                if filterFieldList(t.Fields, f, export) {
136
                        t.Incomplete = true
137
                }
138
                return len(t.Fields.List) > 0
139
        case *FuncType:
140
                b1 := filterParamList(t.Params, f, export)
141
                b2 := filterParamList(t.Results, f, export)
142
                return b1 || b2
143
        case *InterfaceType:
144
                if filterFieldList(t.Methods, f, export) {
145
                        t.Incomplete = true
146
                }
147
                return len(t.Methods.List) > 0
148
        case *MapType:
149
                b1 := filterType(t.Key, f, export)
150
                b2 := filterType(t.Value, f, export)
151
                return b1 || b2
152
        case *ChanType:
153
                return filterType(t.Value, f, export)
154
        }
155
        return false
156
}
157
 
158
func filterSpec(spec Spec, f Filter, export bool) bool {
159
        switch s := spec.(type) {
160
        case *ValueSpec:
161
                s.Names = filterIdentList(s.Names, f)
162
                if len(s.Names) > 0 {
163
                        if export {
164
                                filterType(s.Type, f, export)
165
                        }
166
                        return true
167
                }
168
        case *TypeSpec:
169
                if f(s.Name.Name) {
170
                        if export {
171
                                filterType(s.Type, f, export)
172
                        }
173
                        return true
174
                }
175
                if !export {
176
                        // For general filtering (not just exports),
177
                        // filter type even if name is not filtered
178
                        // out.
179
                        // If the type contains filtered elements,
180
                        // keep the declaration.
181
                        return filterType(s.Type, f, export)
182
                }
183
        }
184
        return false
185
}
186
 
187
func filterSpecList(list []Spec, f Filter, export bool) []Spec {
188
        j := 0
189
        for _, s := range list {
190
                if filterSpec(s, f, export) {
191
                        list[j] = s
192
                        j++
193
                }
194
        }
195
        return list[0:j]
196
}
197
 
198
// FilterDecl trims the AST for a Go declaration in place by removing
199
// all names (including struct field and interface method names, but
200
// not from parameter lists) that don't pass through the filter f.
201
//
202
// FilterDecl returns true if there are any declared names left after
203
// filtering; it returns false otherwise.
204
//
205
func FilterDecl(decl Decl, f Filter) bool {
206
        return filterDecl(decl, f, false)
207
}
208
 
209
func filterDecl(decl Decl, f Filter, export bool) bool {
210
        switch d := decl.(type) {
211
        case *GenDecl:
212
                d.Specs = filterSpecList(d.Specs, f, export)
213
                return len(d.Specs) > 0
214
        case *FuncDecl:
215
                return f(d.Name.Name)
216
        }
217
        return false
218
}
219
 
220
// FilterFile trims the AST for a Go file in place by removing all
221
// names from top-level declarations (including struct field and
222
// interface method names, but not from parameter lists) that don't
223
// pass through the filter f. If the declaration is empty afterwards,
224
// the declaration is removed from the AST. The File.Comments list
225
// is not changed.
226
//
227
// FilterFile returns true if there are any top-level declarations
228
// left after filtering; it returns false otherwise.
229
//
230
func FilterFile(src *File, f Filter) bool {
231
        return filterFile(src, f, false)
232
}
233
 
234
func filterFile(src *File, f Filter, export bool) bool {
235
        j := 0
236
        for _, d := range src.Decls {
237
                if filterDecl(d, f, export) {
238
                        src.Decls[j] = d
239
                        j++
240
                }
241
        }
242
        src.Decls = src.Decls[0:j]
243
        return j > 0
244
}
245
 
246
// FilterPackage trims the AST for a Go package in place by removing
247
// all names from top-level declarations (including struct field and
248
// interface method names, but not from parameter lists) that don't
249
// pass through the filter f. If the declaration is empty afterwards,
250
// the declaration is removed from the AST. The pkg.Files list is not
251
// changed, so that file names and top-level package comments don't get
252
// lost.
253
//
254
// FilterPackage returns true if there are any top-level declarations
255
// left after filtering; it returns false otherwise.
256
//
257
func FilterPackage(pkg *Package, f Filter) bool {
258
        return filterPackage(pkg, f, false)
259
}
260
 
261
func filterPackage(pkg *Package, f Filter, export bool) bool {
262
        hasDecls := false
263
        for _, src := range pkg.Files {
264
                if filterFile(src, f, export) {
265
                        hasDecls = true
266
                }
267
        }
268
        return hasDecls
269
}
270
 
271
// ----------------------------------------------------------------------------
272
// Merging of package files
273
 
274
// The MergeMode flags control the behavior of MergePackageFiles.
275
type MergeMode uint
276
 
277
const (
278
        // If set, duplicate function declarations are excluded.
279
        FilterFuncDuplicates MergeMode = 1 << iota
280
        // If set, comments that are not associated with a specific
281
        // AST node (as Doc or Comment) are excluded.
282
        FilterUnassociatedComments
283
        // If set, duplicate import declarations are excluded.
284
        FilterImportDuplicates
285
)
286
 
287
// separator is an empty //-style comment that is interspersed between
288
// different comment groups when they are concatenated into a single group
289
//
290
var separator = &Comment{noPos, "//"}
291
 
292
// MergePackageFiles creates a file AST by merging the ASTs of the
293
// files belonging to a package. The mode flags control merging behavior.
294
//
295
func MergePackageFiles(pkg *Package, mode MergeMode) *File {
296
        // Count the number of package docs, comments and declarations across
297
        // all package files. Also, compute sorted list of filenames, so that
298
        // subsequent iterations can always iterate in the same order.
299
        ndocs := 0
300
        ncomments := 0
301
        ndecls := 0
302
        filenames := make([]string, len(pkg.Files))
303
        i := 0
304
        for filename, f := range pkg.Files {
305
                filenames[i] = filename
306
                i++
307
                if f.Doc != nil {
308
                        ndocs += len(f.Doc.List) + 1 // +1 for separator
309
                }
310
                ncomments += len(f.Comments)
311
                ndecls += len(f.Decls)
312
        }
313
        sort.Strings(filenames)
314
 
315
        // Collect package comments from all package files into a single
316
        // CommentGroup - the collected package documentation. In general
317
        // there should be only one file with a package comment; but it's
318
        // better to collect extra comments than drop them on the floor.
319
        var doc *CommentGroup
320
        var pos token.Pos
321
        if ndocs > 0 {
322
                list := make([]*Comment, ndocs-1) // -1: no separator before first group
323
                i := 0
324
                for _, filename := range filenames {
325
                        f := pkg.Files[filename]
326
                        if f.Doc != nil {
327
                                if i > 0 {
328
                                        // not the first group - add separator
329
                                        list[i] = separator
330
                                        i++
331
                                }
332
                                for _, c := range f.Doc.List {
333
                                        list[i] = c
334
                                        i++
335
                                }
336
                                if f.Package > pos {
337
                                        // Keep the maximum package clause position as
338
                                        // position for the package clause of the merged
339
                                        // files.
340
                                        pos = f.Package
341
                                }
342
                        }
343
                }
344
                doc = &CommentGroup{list}
345
        }
346
 
347
        // Collect declarations from all package files.
348
        var decls []Decl
349
        if ndecls > 0 {
350
                decls = make([]Decl, ndecls)
351
                funcs := make(map[string]int) // map of global function name -> decls index
352
                i := 0                        // current index
353
                n := 0                        // number of filtered entries
354
                for _, filename := range filenames {
355
                        f := pkg.Files[filename]
356
                        for _, d := range f.Decls {
357
                                if mode&FilterFuncDuplicates != 0 {
358
                                        // A language entity may be declared multiple
359
                                        // times in different package files; only at
360
                                        // build time declarations must be unique.
361
                                        // For now, exclude multiple declarations of
362
                                        // functions - keep the one with documentation.
363
                                        //
364
                                        // TODO(gri): Expand this filtering to other
365
                                        //            entities (const, type, vars) if
366
                                        //            multiple declarations are common.
367
                                        if f, isFun := d.(*FuncDecl); isFun {
368
                                                name := f.Name.Name
369
                                                if j, exists := funcs[name]; exists {
370
                                                        // function declared already
371
                                                        if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil {
372
                                                                // existing declaration has no documentation;
373
                                                                // ignore the existing declaration
374
                                                                decls[j] = nil
375
                                                        } else {
376
                                                                // ignore the new declaration
377
                                                                d = nil
378
                                                        }
379
                                                        n++ // filtered an entry
380
                                                } else {
381
                                                        funcs[name] = i
382
                                                }
383
                                        }
384
                                }
385
                                decls[i] = d
386
                                i++
387
                        }
388
                }
389
 
390
                // Eliminate nil entries from the decls list if entries were
391
                // filtered. We do this using a 2nd pass in order to not disturb
392
                // the original declaration order in the source (otherwise, this
393
                // would also invalidate the monotonically increasing position
394
                // info within a single file).
395
                if n > 0 {
396
                        i = 0
397
                        for _, d := range decls {
398
                                if d != nil {
399
                                        decls[i] = d
400
                                        i++
401
                                }
402
                        }
403
                        decls = decls[0:i]
404
                }
405
        }
406
 
407
        // Collect import specs from all package files.
408
        var imports []*ImportSpec
409
        if mode&FilterImportDuplicates != 0 {
410
                seen := make(map[string]bool)
411
                for _, filename := range filenames {
412
                        f := pkg.Files[filename]
413
                        for _, imp := range f.Imports {
414
                                if path := imp.Path.Value; !seen[path] {
415
                                        // TODO: consider handling cases where:
416
                                        // - 2 imports exist with the same import path but
417
                                        //   have different local names (one should probably
418
                                        //   keep both of them)
419
                                        // - 2 imports exist but only one has a comment
420
                                        // - 2 imports exist and they both have (possibly
421
                                        //   different) comments
422
                                        imports = append(imports, imp)
423
                                        seen[path] = true
424
                                }
425
                        }
426
                }
427
        } else {
428
                for _, f := range pkg.Files {
429
                        imports = append(imports, f.Imports...)
430
                }
431
        }
432
 
433
        // Collect comments from all package files.
434
        var comments []*CommentGroup
435
        if mode&FilterUnassociatedComments == 0 {
436
                comments = make([]*CommentGroup, ncomments)
437
                i := 0
438
                for _, f := range pkg.Files {
439
                        i += copy(comments[i:], f.Comments)
440
                }
441
        }
442
 
443
        // TODO(gri) need to compute unresolved identifiers!
444
        return &File{doc, pos, NewIdent(pkg.Name), decls, pkg.Scope, imports, nil, comments}
445
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.