8 func (smith *Smith) initExpressions() {
9 smith.expressions = []func(res *Type) string{
13 smith.exprSelectorField,
19 smith.exprCallBuiltin,
25 smith.exprIndexString,
31 func (smith *Smith) expression(res *Type) string {
33 smith.totalExprCount++
34 if smith.exprDepth >= NExprDepth || smith.exprCount >= NExprCount || smith.totalExprCount >= NTotalExprCount {
39 s := smith.expressions[smith.rnd(len(smith.expressions))](res)
47 func (smith *Smith) rvalue(t *Type) string {
48 return smith.expression(t)
51 // rvalue, but not a const
52 // used to index arrays and strings
53 func (smith *Smith) nonconstRvalue(t *Type) string {
54 if t.class != ClassNumeric {
60 switch smith.choice("lvalue", "call", "len", "selector", "recv", "arith", "indexMap", "conv") {
64 res = smith.exprCall(t)
66 tt := smith.atype(TraitLenCapable)
67 fn := smith.choice("len", "cap")
68 if (tt.class == ClassString || tt.class == ClassMap) && fn == "cap" {
71 if tt.class == ClassArray {
75 res = F("(%v)((%v)(%v))", t.id, fn, smith.lvalue(tt))
77 res = smith.exprSelectorField(t)
79 res = smith.exprRecv(t)
81 res = F("(%v) %v (%v)", smith.lvalue(t), smith.choice("+", "-"), smith.rvalue(t))
83 res = smith.exprIndexMap(t)
85 res = F("(%v)(%v %v)", t.id, smith.lvalue(smith.atype(ClassNumeric)), smith.choice("", ","))
96 func (smith *Smith) lvalue(t *Type) string {
98 switch smith.choice("var", "indexSlice", "indexArray", "selector", "deref") {
100 return smith.exprVar(t)
102 return smith.exprIndexSlice(t)
104 return F("(%v)[%v]", smith.lvalue(smith.arrayOf(t)), smith.nonconstRvalue(smith.intType))
106 for i := 0; i < 10; i++ {
107 st := smith.atype(ClassStruct)
108 for _, e := range st.elems {
110 return F("(%v).%v", smith.lvalue(st), e.id)
116 return smith.exprDeref(t)
123 func (smith *Smith) lvalueOrBlank(t *Type) string {
125 switch smith.choice("lvalue", "map", "blank") {
127 return smith.lvalue(t)
129 if e := smith.exprIndexMap(t); e != "" {
140 func (smith *Smith) lvalueOrMapIndex(t *Type) string {
142 switch smith.choice("lvalue", "map") {
144 return smith.lvalue(t)
146 if e := smith.exprIndexMap(t); e != "" {
155 func (smith *Smith) fmtRvalueList(list []*Type) string {
157 for i, t := range list {
159 buf.Write([]byte{','})
161 fmt.Fprintf(&buf, "%v", smith.rvalue(t))
166 func (smith *Smith) fmtLvalueList(list []*Type) string {
168 for i, t := range list {
170 buf.Write([]byte{','})
172 buf.WriteString(smith.lvalueOrBlank(t))
177 func (smith *Smith) fmtOasVarList(list []*Type) (str string, newVars []*Var) {
178 allVars := smith.vars()
180 for i, t := range list {
182 // First, try to find an existing var in the same scope.
184 for i, v := range allVars {
185 if v.typ == t && v.block == smith.curBlock {
186 allVars[i] = allVars[len(allVars)-1]
187 allVars = allVars[:len(allVars)-1]
193 if smith.rndBool() || (i == len(list)-1 && len(newVars) == 0) {
194 expr = smith.newId("Var")
195 newVars = append(newVars, &Var{id: expr, typ: t})
199 buf.WriteString(", ")
201 buf.WriteString(expr)
203 return buf.String(), newVars
206 func (smith *Smith) exprLiteral(res *Type) string {
207 if res.complexLiteral != nil {
208 return res.complexLiteral()
213 func (smith *Smith) exprVar(res *Type) string {
214 for _, v := range smith.vars() {
219 return smith.materializeVar(res)
222 func (smith *Smith) exprSelectorField(res *Type) string {
223 for i := 0; i < 10; i++ {
224 st := smith.atype(ClassStruct)
225 for _, e := range st.elems {
227 return F("(%v).%v", smith.rvalue(st), e.id)
234 func (smith *Smith) exprFunc(res *Type) string {
235 if !smith.satisfiesTrait(res, TraitGlobal) {
239 for _, f1 := range smith.packages[smith.curPackage].toplevFuncs {
240 if len(f1.rets) == 1 && f1.rets[0] == res {
246 f = smith.materializeFunc([]*Type{res})
249 return F("%v(%v)", f.name, smith.fmtRvalueList(f.args))
253 for _, f1 := range smith.packages[smith.curPackage].toplevFuncs {
254 if len(f1.rets) == len(f.args) {
255 for i := range f.args {
256 // TODO: check assignability
257 if f1.rets[i] != f.args[i] {
266 f0 = smith.materializeFunc(f.args)
268 return F("%v(%v(%v))", f.name, f0.name, smith.fmtRvalueList(f0.args))
272 func (smith *Smith) exprAddress(res *Type) string {
273 if res.class != ClassPointer {
276 if res.ktyp.class == ClassStruct && smith.rndBool() {
277 return F("&%v", res.ktyp.complexLiteral())
279 return F("(%v)(&(%v))", res.id, smith.lvalue(res.ktyp))
282 func (smith *Smith) exprDeref(res *Type) string {
283 return F("(*(%v))", smith.lvalue(pointerTo(res)))
286 func (smith *Smith) exprRecv(res *Type) string {
287 t := smith.chanOf(res)
288 return F("(<- %v)", smith.rvalue(t))
291 func (smith *Smith) exprArith(res *Type) string {
292 if res.class != ClassNumeric && res.class != ClassComplex {
295 // "/" causes division by zero
296 // "*" causes generation of -1 index in int(real(1i * 1i))
297 return F("(%v) + (%v)", smith.rvalue(res), smith.rvalue(res))
300 func (smith *Smith) exprEqual(res *Type) string {
301 if res != smith.boolType {
304 t := smith.atype(TraitComparable)
305 return F("(%v) %v (%v)", smith.rvalue(t), smith.choice("==", "!="), smith.rvalue(t))
308 func (smith *Smith) exprOrder(res *Type) string {
309 if res != smith.boolType {
312 t := smith.atype(TraitOrdered)
313 return F("(%v) %v (%v)", smith.rvalue(t), smith.choice("<", "<=", ">", ">="), smith.rvalue(t))
317 func (smith *Smith) exprCall(ret *Type) string {
318 t := smith.funcOf(smith.atypeList(TraitAny), []*Type{ret})
319 return F("%v(%v)", smith.rvalue(t), smith.fmtRvalueList(t.styp))
322 func (smith *Smith) exprCallBuiltin(ret *Type) string {
323 switch fn := smith.choice("append", "cap", "complex", "copy", "imag", "len", "make", "new", "real", "recover"); fn {
325 if ret.class != ClassSlice {
328 switch smith.choice("one", "two", "slice") {
330 return F("%v(%v, %v)", fn, smith.rvalue(ret), smith.rvalue(ret.ktyp))
332 return F("%v(%v, %v, %v)", fn, smith.rvalue(ret), smith.rvalue(ret.ktyp), smith.rvalue(ret.ktyp))
334 return F("%v(%v, %v...)", fn, smith.rvalue(ret), smith.rvalue(ret))
339 if ret != smith.intType { // TODO: must be convertable
342 t := smith.atype(TraitLenCapable)
343 if (t.class == ClassString || t.class == ClassMap) && fn == "cap" {
347 return F("%v(%v)", fn, smith.rvalue(t))
349 if ret != smith.intType {
352 return F("%v", smith.exprCopySlice())
354 if ret.class != ClassSlice && ret.class != ClassMap && ret.class != ClassChan {
358 if ret.class == ClassSlice {
360 cap = F(", %v", smith.rvalue(smith.intType))
362 // Careful to not generate "len larger than cap".
363 cap = F(", 0, %v", smith.rvalue(smith.intType))
365 } else if smith.rndBool() {
366 cap = F(", %v", smith.rvalue(smith.intType))
368 return F("make(%v %v)", ret.id, cap)
370 if ret.class != ClassPointer {
373 return F("new(%v)", ret.ktyp.id)
375 if ret != smith.efaceType {
380 if ret == smith.float32Type {
381 return F("real(%v)", smith.rvalue(smith.complex64Type))
383 if ret == smith.float64Type {
384 return F("real(%v)", smith.rvalue(smith.complex128Type))
388 if ret == smith.complex64Type {
389 return F("complex(%v, %v)", smith.rvalue(smith.float32Type), smith.rvalue(smith.float32Type))
391 if ret == smith.complex128Type {
392 return F("complex(%v, %v)", smith.rvalue(smith.float64Type), smith.rvalue(smith.float64Type))
400 func (smith *Smith) exprCopySlice() string {
402 t := smith.atype(ClassSlice)
403 return F("copy(%v, %v)", smith.rvalue(t), smith.rvalue(t))
405 return F("copy(%v, %v)", smith.rvalue(smith.sliceOf(smith.byteType)), smith.rvalue(smith.stringType))
409 func (smith *Smith) exprSlice(ret *Type) string {
410 if ret.class != ClassSlice {
415 i0 = smith.nonconstRvalue(smith.intType)
419 i2 = ":" + smith.nonconstRvalue(smith.intType)
422 if smith.rndBool() || i2 != "" {
423 i1 = ":" + smith.nonconstRvalue(smith.intType)
425 return F("(%v)[%v%v%v]", smith.rvalue(ret), i0, i1, i2)
428 func (smith *Smith) exprIndexSlice(ret *Type) string {
429 return F("(%v)[%v]", smith.rvalue(smith.sliceOf(ret)), smith.nonconstRvalue(smith.intType))
432 func (smith *Smith) exprIndexString(ret *Type) string {
433 if ret != smith.byteType {
436 return F("(%v)[%v]", smith.rvalue(smith.stringType), smith.nonconstRvalue(smith.intType))
439 func (smith *Smith) exprIndexArray(ret *Type) string {
440 // TODO: also handle indexing of pointers to arrays
441 return F("(%v)[%v]", smith.rvalue(smith.arrayOf(ret)), smith.nonconstRvalue(smith.intType))
444 func (smith *Smith) exprIndexMap(ret *Type) string {
445 // TODO: figure out something better
446 for i := 0; i < 10; i++ {
447 t := smith.atype(ClassMap)
449 return F("(%v)[%v]", smith.rvalue(t), smith.rvalue(t.ktyp))
455 func (smith *Smith) exprConversion(ret *Type) string {
456 if ret.class == ClassNumeric {
457 return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.atype(ClassNumeric)), smith.choice("", ","))
459 if ret.class == ClassComplex {
460 return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.atype(ClassComplex)), smith.choice("", ","))
462 if ret == smith.stringType {
463 switch smith.choice("int", "byteSlice", "runeSlice") {
465 // We produce a string of length at least 3, to not produce
466 // "invalid string index 1 (out of bounds for 1-byte string)"
467 return F("(%v)((%v) + (1<<24) %v)", ret.id, smith.rvalue(smith.intType), smith.choice("", ","))
469 return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.sliceOf(smith.byteType)), smith.choice("", ","))
471 return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.sliceOf(smith.runeType)), smith.choice("", ","))
476 if ret.class == ClassSlice && (ret.ktyp == smith.byteType || ret.ktyp == smith.runeType) {
477 return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.stringType), smith.choice("", ","))
479 // TODO: handle "x is assignable to T"
480 // TODO: handle "x's type and T have identical underlying types"
481 // TODO: handle "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"