1
2
3
4
5 package specgen
6
7 import (
8 "cmp"
9 "errors"
10 "fmt"
11 "go/ast"
12 "go/token"
13 "io"
14 "maps"
15 "simd/archsimd/_gen/specgen/specexpr"
16 "slices"
17 "strings"
18 )
19
20 type LoadOptions struct {
21
22
23 Filter func(*ast.FuncDecl) bool
24
25
26
27 Trace io.Writer
28 }
29
30
31
32 func Load(dir string, opts *LoadOptions) ([]*Func, error) {
33 if opts == nil {
34 opts = new(LoadOptions)
35 }
36
37 var root contextRoot
38 ctx := context{root: &root}
39
40 pkg := loadSpecPackage(ctx, dir, opts)
41 if err := root.gatherErrors(); err != nil {
42 return nil, err
43 }
44
45 var allFuncs []*Func
46 type funcKey struct {
47 recv specexpr.Type
48 name string
49 }
50 funcSet := make(map[funcKey]*Func)
51 for _, sFn := range pkg.Funcs {
52 expanded := sFn.expand(ctx, opts)
53
54
55 for _, fn := range expanded {
56 key := funcKey{fn.Recv.Type, fn.Name}
57 if ofn := funcSet[key]; ofn != nil {
58 ctx.at(sFn.Pos).errorf("conflicting functions:\n\t%s\n\t%s", fn.Signature(), ofn.Signature())
59 continue
60 }
61 funcSet[key] = fn
62 allFuncs = append(allFuncs, fn)
63 }
64 }
65
66 return allFuncs, root.gatherErrors()
67 }
68
69 type contextRoot struct {
70 fset token.FileSet
71 errors map[srcError]struct{}
72 }
73
74 type context struct {
75 root *contextRoot
76 pos token.Pos
77 fn string
78 }
79
80 func (c context) at(pos token.Pos) context {
81 c.pos = pos
82 return c
83 }
84
85 func (c context) errorf(msg string, args ...any) {
86 if c.root.errors == nil {
87 c.root.errors = make(map[srcError]struct{})
88 }
89 err := srcError{c.pos, c.fn, fmt.Sprintf(msg, args...)}
90 c.root.errors[err] = struct{}{}
91 }
92
93 func (r *contextRoot) gatherErrors() error {
94 if len(r.errors) == 0 {
95 return nil
96 }
97 var errs []error
98 var buf strings.Builder
99 for _, err := range slices.SortedFunc(maps.Keys(r.errors), func(a, b srcError) int {
100 return cmp.Or(cmp.Compare(a.pos, b.pos), cmp.Compare(a.msg, b.msg))
101 }) {
102 if err.pos.IsValid() {
103 fmt.Fprintf(&buf, "%s: ", r.fset.Position(err.pos))
104 }
105 buf.WriteString(err.msg)
106 if err.fn != "" {
107 fmt.Fprintf(&buf, " in %s", err.fn)
108 }
109 errs = append(errs, fmt.Errorf("%s", buf.String()))
110 buf.Reset()
111 }
112 return errors.Join(errs...)
113 }
114
115 type srcError struct {
116 pos token.Pos
117 fn string
118 msg string
119 }
120
View as plain text