|
1 |
| -package microsmith |
2 |
| - |
3 |
| -import ( |
4 |
| - "math/rand" |
5 |
| - "strconv" |
6 |
| -) |
7 |
| - |
8 |
| -// Context holds all the contextual information needed while |
9 |
| -// generating a random package. |
10 |
| -type Context struct { // TODO(alb): rename to PackageContext |
11 |
| - |
12 |
| - // program-wide settings for the fuzzer |
13 |
| - programConf ProgramConf |
14 |
| - |
15 |
| - // all the Costraints available declared in the package |
16 |
| - constraints []Constraint |
17 |
| - |
18 |
| - // package-wide scope of vars and func available to the code in a |
19 |
| - // given moment |
20 |
| - scope *Scope |
21 |
| - |
22 |
| - // Function-level scope of the type parameters available to the |
23 |
| - // code in the body. Reset and re-filled in when declaring a new |
24 |
| - // function. |
25 |
| - typeparams *Scope |
26 |
| -} |
27 |
| - |
28 |
| -func NewContext(pc ProgramConf) *Context { |
29 |
| - return &Context{ |
30 |
| - programConf: pc, |
31 |
| - } |
32 |
| -} |
33 |
| - |
34 |
| -// ProgramConf holds program-wide configuration settings that change |
35 |
| -// the kind of programs that are generated. |
36 |
| -type ProgramConf struct { |
37 |
| - MultiPkg bool // for -multipkg |
38 |
| - TypeParams bool // for -tp |
39 |
| -} |
40 |
| - |
41 |
| -// -------------------------------- |
42 |
| -// Types Randomizers |
43 |
| -// -------------------------------- |
44 |
| - |
45 |
| -// Returns a slice of n random types, including composite types |
46 |
| -// (structs, array, maps, chans). |
47 |
| -func (pb PackageBuilder) RandTypes(n int) []Type { |
48 |
| - types := make([]Type, n) |
49 |
| - for i := 0; i < n; i++ { |
50 |
| - types[i] = pb.RandType() |
51 |
| - } |
52 |
| - return types |
53 |
| -} |
54 |
| - |
55 |
| -// Returns a single random type (including structs, array, maps, |
56 |
| -// chans). |
57 |
| -func (pb PackageBuilder) RandType() Type { |
58 |
| - pb.typedepth++ |
59 |
| - defer func() { pb.typedepth-- }() |
60 |
| - |
61 |
| - if pb.typedepth >= 5 { |
62 |
| - return pb.RandBaseType() |
63 |
| - } |
64 |
| - |
65 |
| - switch pb.rs.Intn(15) { |
66 |
| - case 0, 1: |
67 |
| - return ArrayOf(pb.RandType()) |
68 |
| - case 2: |
69 |
| - return ChanOf(pb.RandType()) |
70 |
| - case 3, 4: |
71 |
| - return MapOf( |
72 |
| - pb.RandAddressableType(), |
73 |
| - pb.RandType(), |
74 |
| - ) |
75 |
| - case 5, 6: |
76 |
| - return PointerOf(pb.RandType()) |
77 |
| - case 7, 8: |
78 |
| - return pb.RandStructType() |
79 |
| - case 9: |
80 |
| - return pb.RandFuncType() |
81 |
| - default: |
82 |
| - return pb.RandBaseType() |
83 |
| - } |
84 |
| -} |
85 |
| - |
86 |
| -func (pb PackageBuilder) RandAddressableType() Type { |
87 |
| - types := make([]Type, 0, 32) |
88 |
| - |
89 |
| - // collect addressable Base Types |
90 |
| - for _, t := range pb.baseTypes { |
91 |
| - if t.Addressable() { |
92 |
| - types = append(types, t) |
93 |
| - } |
94 |
| - } |
95 |
| - |
96 |
| - // look for addressable type parameters |
97 |
| - if tp := pb.ctx.typeparams; tp != nil { |
98 |
| - for _, v := range *tp { |
99 |
| - if v.Type.Addressable() { |
100 |
| - types = append(types, MakeTypeParam(v)) |
101 |
| - } |
102 |
| - } |
103 |
| - } |
104 |
| - |
105 |
| - return types[pb.rs.Intn(len(types))] |
106 |
| -} |
107 |
| - |
108 |
| -// Returns a single BaseType (primitives, or a type parameter). |
109 |
| -func (pb PackageBuilder) RandBaseType() Type { |
110 |
| - if tp := pb.ctx.typeparams; tp != nil { |
111 |
| - i := pb.rs.Intn(len(pb.baseTypes) + len(*tp)) |
112 |
| - if i < len(pb.baseTypes) { |
113 |
| - return pb.baseTypes[i] |
114 |
| - } else { |
115 |
| - return MakeTypeParam((*tp)[i-len(pb.baseTypes)]) |
116 |
| - } |
117 |
| - } else { |
118 |
| - return pb.baseTypes[rand.Intn(len(pb.baseTypes))] |
119 |
| - } |
120 |
| -} |
121 |
| - |
122 |
| -func (pb PackageBuilder) RandStructType() StructType { |
123 |
| - st := StructType{"ST", []Type{}, []string{}} |
124 |
| - for i := 0; i < pb.rs.Intn(6); i++ { |
125 |
| - t := pb.RandType() |
126 |
| - st.Ftypes = append(st.Ftypes, t) |
127 |
| - st.Fnames = append(st.Fnames, Ident(t)+strconv.Itoa(i)) |
128 |
| - } |
129 |
| - return st |
130 |
| -} |
131 |
| - |
132 |
| -func (pb PackageBuilder) RandFuncType() FuncType { |
133 |
| - args := make([]Type, 0, pb.rs.Intn(8)) |
134 |
| - |
135 |
| - // arguments |
136 |
| - for i := 0; i < cap(args); i++ { |
137 |
| - args = append(args, pb.RandType()) |
138 |
| - } |
139 |
| - |
140 |
| - // optionally make the last parameter variadic |
141 |
| - if len(args) > 0 && pb.rs.Intn(4) == 0 { |
142 |
| - args[len(args)-1] = EllipsisType{Base: args[len(args)-1]} |
143 |
| - } |
144 |
| - |
145 |
| - // return type |
146 |
| - ret := []Type{pb.RandType()} |
147 |
| - |
148 |
| - return FuncType{"FU", args, ret, true} |
149 |
| -} |
| 1 | +package microsmith |
| 2 | + |
| 3 | +import ( |
| 4 | + "math/rand" |
| 5 | + "strconv" |
| 6 | +) |
| 7 | + |
| 8 | +// Context holds all the contextual information needed while |
| 9 | +// generating a random package. |
| 10 | +type Context struct { // TODO(alb): rename to PackageContext |
| 11 | + |
| 12 | + // program-wide settings for the fuzzer |
| 13 | + programConf ProgramConf |
| 14 | + |
| 15 | + // all the Costraints available declared in the package |
| 16 | + constraints []Constraint |
| 17 | + |
| 18 | + // package-wide scope of vars and func available to the code in a |
| 19 | + // given moment |
| 20 | + scope *Scope |
| 21 | + |
| 22 | + // Function-level scope of the type parameters available to the |
| 23 | + // code in the body. Reset and re-filled in when declaring a new |
| 24 | + // function. |
| 25 | + typeparams *Scope |
| 26 | +} |
| 27 | + |
| 28 | +func NewContext(pc ProgramConf) *Context { |
| 29 | + return &Context{ |
| 30 | + programConf: pc, |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +// ProgramConf holds program-wide configuration settings that change |
| 35 | +// the kind of programs that are generated. |
| 36 | +type ProgramConf struct { |
| 37 | + MultiPkg bool // for -multipkg |
| 38 | + TypeParams bool // for -tp |
| 39 | +} |
| 40 | + |
| 41 | +// -------------------------------- |
| 42 | +// Randomizers |
| 43 | +// -------------------------------- |
| 44 | + |
| 45 | +func RandItem[T any](r *rand.Rand, a []T) T { |
| 46 | + if r == nil { |
| 47 | + panic("RandItem called with nil rand.Rand") |
| 48 | + } |
| 49 | + return a[r.Intn(len(a))] |
| 50 | +} |
| 51 | + |
| 52 | +// -------------------------------- |
| 53 | +// Types Randomizers |
| 54 | +// -------------------------------- |
| 55 | + |
| 56 | +// Returns a slice of n random types, including composite types |
| 57 | +// (structs, array, maps, chans). |
| 58 | +func (pb PackageBuilder) RandTypes(n int) []Type { |
| 59 | + types := make([]Type, n) |
| 60 | + for i := 0; i < n; i++ { |
| 61 | + types[i] = pb.RandType() |
| 62 | + } |
| 63 | + return types |
| 64 | +} |
| 65 | + |
| 66 | +// Returns a single random type (including structs, array, maps, |
| 67 | +// chans). |
| 68 | +func (pb PackageBuilder) RandType() Type { |
| 69 | + pb.typedepth++ |
| 70 | + defer func() { pb.typedepth-- }() |
| 71 | + |
| 72 | + if pb.typedepth >= 5 { |
| 73 | + return pb.RandBaseType() |
| 74 | + } |
| 75 | + |
| 76 | + switch pb.rs.Intn(15) { |
| 77 | + case 0, 1: |
| 78 | + return ArrayOf(pb.RandType()) |
| 79 | + case 2: |
| 80 | + return ChanOf(pb.RandType()) |
| 81 | + case 3, 4: |
| 82 | + return MapOf( |
| 83 | + pb.RandAddressableType(), |
| 84 | + pb.RandType(), |
| 85 | + ) |
| 86 | + case 5, 6: |
| 87 | + return PointerOf(pb.RandType()) |
| 88 | + case 7, 8: |
| 89 | + return pb.RandStructType() |
| 90 | + case 9: |
| 91 | + return pb.RandFuncType() |
| 92 | + default: |
| 93 | + return pb.RandBaseType() |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +func (pb PackageBuilder) RandAddressableType() Type { |
| 98 | + types := make([]Type, 0, 32) |
| 99 | + |
| 100 | + // collect addressable Base Types |
| 101 | + for _, t := range pb.baseTypes { |
| 102 | + if t.Addressable() { |
| 103 | + types = append(types, t) |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + // look for addressable type parameters |
| 108 | + if tp := pb.ctx.typeparams; tp != nil { |
| 109 | + for _, v := range tp.vars { |
| 110 | + if v.Type.Addressable() { |
| 111 | + types = append(types, MakeTypeParam(v)) |
| 112 | + } |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + return RandItem(pb.rs, types) |
| 117 | +} |
| 118 | + |
| 119 | +// Returns a single BaseType (primitives, or a type parameter). |
| 120 | +func (pb PackageBuilder) RandBaseType() Type { |
| 121 | + if tp := pb.ctx.typeparams; tp != nil { |
| 122 | + i := pb.rs.Intn(len(pb.baseTypes) + len(tp.vars)) |
| 123 | + if i < len(pb.baseTypes) { |
| 124 | + return pb.baseTypes[i] |
| 125 | + } else { |
| 126 | + return MakeTypeParam((tp.vars)[i-len(pb.baseTypes)]) |
| 127 | + } |
| 128 | + } else { |
| 129 | + return RandItem(pb.rs, pb.baseTypes) |
| 130 | + } |
| 131 | +} |
| 132 | + |
| 133 | +func (pb PackageBuilder) RandStructType() StructType { |
| 134 | + st := StructType{"ST", []Type{}, []string{}} |
| 135 | + for i := 0; i < pb.rs.Intn(6); i++ { |
| 136 | + t := pb.RandType() |
| 137 | + st.Ftypes = append(st.Ftypes, t) |
| 138 | + st.Fnames = append(st.Fnames, Ident(t)+strconv.Itoa(i)) |
| 139 | + } |
| 140 | + return st |
| 141 | +} |
| 142 | + |
| 143 | +func (pb PackageBuilder) RandFuncType() FuncType { |
| 144 | + args := make([]Type, 0, pb.rs.Intn(8)) |
| 145 | + |
| 146 | + // arguments |
| 147 | + for i := 0; i < cap(args); i++ { |
| 148 | + args = append(args, pb.RandType()) |
| 149 | + } |
| 150 | + |
| 151 | + // optionally make the last parameter variadic |
| 152 | + if len(args) > 0 && pb.rs.Intn(4) == 0 { |
| 153 | + args[len(args)-1] = EllipsisType{Base: args[len(args)-1]} |
| 154 | + } |
| 155 | + |
| 156 | + // return type |
| 157 | + ret := []Type{pb.RandType()} |
| 158 | + |
| 159 | + return FuncType{"FU", args, ret, true} |
| 160 | +} |
0 commit comments