1package main
2
3import (
4	"bytes"
5	"fmt"
6)
7
8func (smith *Smith) initExpressions() {
9	smith.expressions = []func(res *Type) string{
10		smith.exprLiteral,
11		smith.exprVar,
12		smith.exprFunc,
13		smith.exprSelectorField,
14		smith.exprRecv,
15		smith.exprArith,
16		smith.exprEqual,
17		smith.exprOrder,
18		smith.exprCall,
19		smith.exprCallBuiltin,
20		smith.exprAddress,
21		smith.exprDeref,
22		smith.exprSlice,
23		smith.exprIndexSlice,
24		smith.exprIndexArray,
25		smith.exprIndexString,
26		smith.exprIndexMap,
27		smith.exprConversion,
28	}
29}
30
31func (smith *Smith) expression(res *Type) string {
32	smith.exprCount++
33	smith.totalExprCount++
34	if smith.exprDepth >= NExprDepth || smith.exprCount >= NExprCount || smith.totalExprCount >= NTotalExprCount {
35		return res.literal()
36	}
37	for {
38		smith.exprDepth++
39		s := smith.expressions[smith.rnd(len(smith.expressions))](res)
40		smith.exprDepth--
41		if s != "" {
42			return s
43		}
44	}
45}
46
47func (smith *Smith) rvalue(t *Type) string {
48	return smith.expression(t)
49}
50
51// rvalue, but not a const
52// used to index arrays and strings
53func (smith *Smith) nonconstRvalue(t *Type) string {
54	if t.class != ClassNumeric {
55		panic("bad")
56	}
57trying:
58	for {
59		res := ""
60		switch smith.choice("lvalue", "call", "len", "selector", "recv", "arith", "indexMap", "conv") {
61		case "lvalue":
62			res = smith.lvalue(t)
63		case "call":
64			res = smith.exprCall(t)
65		case "len":
66			tt := smith.atype(TraitLenCapable)
67			fn := smith.choice("len", "cap")
68			if (tt.class == ClassString || tt.class == ClassMap) && fn == "cap" {
69				break
70			}
71			if tt.class == ClassArray {
72				// len/cap are const
73				break
74			}
75			res = F("(%v)((%v)(%v))", t.id, fn, smith.lvalue(tt))
76		case "selector":
77			res = smith.exprSelectorField(t)
78		case "recv":
79			res = smith.exprRecv(t)
80		case "arith":
81			res = F("(%v) %v (%v)", smith.lvalue(t), smith.choice("+", "-"), smith.rvalue(t))
82		case "indexMap":
83			res = smith.exprIndexMap(t)
84		case "conv":
85			res = F("(%v)(%v %v)", t.id, smith.lvalue(smith.atype(ClassNumeric)), smith.choice("", ","))
86		default:
87			panic("bad")
88		}
89		if res == "" {
90			continue trying
91		}
92		return res
93	}
94}
95
96func (smith *Smith) lvalue(t *Type) string {
97	for {
98		switch smith.choice("var", "indexSlice", "indexArray", "selector", "deref") {
99		case "var":
100			return smith.exprVar(t)
101		case "indexSlice":
102			return smith.exprIndexSlice(t)
103		case "indexArray":
104			return F("(%v)[%v]", smith.lvalue(smith.arrayOf(t)), smith.nonconstRvalue(smith.intType))
105		case "selector":
106			for i := 0; i < 10; i++ {
107				st := smith.atype(ClassStruct)
108				for _, e := range st.elems {
109					if e.typ == t {
110						return F("(%v).%v", smith.lvalue(st), e.id)
111					}
112				}
113			}
114			continue
115		case "deref":
116			return smith.exprDeref(t)
117		default:
118			panic("bad")
119		}
120	}
121}
122
123func (smith *Smith) lvalueOrBlank(t *Type) string {
124	for {
125		switch smith.choice("lvalue", "map", "blank") {
126		case "lvalue":
127			return smith.lvalue(t)
128		case "map":
129			if e := smith.exprIndexMap(t); e != "" {
130				return e
131			}
132		case "blank":
133			return "_"
134		default:
135			panic("bad")
136		}
137	}
138}
139
140func (smith *Smith) lvalueOrMapIndex(t *Type) string {
141	for {
142		switch smith.choice("lvalue", "map") {
143		case "lvalue":
144			return smith.lvalue(t)
145		case "map":
146			if e := smith.exprIndexMap(t); e != "" {
147				return e
148			}
149		default:
150			panic("bad")
151		}
152	}
153}
154
155func (smith *Smith) fmtRvalueList(list []*Type) string {
156	var buf bytes.Buffer
157	for i, t := range list {
158		if i != 0 {
159			buf.Write([]byte{','})
160		}
161		fmt.Fprintf(&buf, "%v", smith.rvalue(t))
162	}
163	return buf.String()
164}
165
166func (smith *Smith) fmtLvalueList(list []*Type) string {
167	var buf bytes.Buffer
168	for i, t := range list {
169		if i != 0 {
170			buf.Write([]byte{','})
171		}
172		buf.WriteString(smith.lvalueOrBlank(t))
173	}
174	return buf.String()
175}
176
177func (smith *Smith) fmtOasVarList(list []*Type) (str string, newVars []*Var) {
178	allVars := smith.vars()
179	var buf bytes.Buffer
180	for i, t := range list {
181		expr := "_"
182		// First, try to find an existing var in the same scope.
183		if smith.rndBool() {
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]
188					expr = v.id
189					break
190				}
191			}
192		}
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})
196		}
197
198		if i != 0 {
199			buf.WriteString(", ")
200		}
201		buf.WriteString(expr)
202	}
203	return buf.String(), newVars
204}
205
206func (smith *Smith) exprLiteral(res *Type) string {
207	if res.complexLiteral != nil {
208		return res.complexLiteral()
209	}
210	return res.literal()
211}
212
213func (smith *Smith) exprVar(res *Type) string {
214	for _, v := range smith.vars() {
215		if v.typ == res {
216			return v.id
217		}
218	}
219	return smith.materializeVar(res)
220}
221
222func (smith *Smith) exprSelectorField(res *Type) string {
223	for i := 0; i < 10; i++ {
224		st := smith.atype(ClassStruct)
225		for _, e := range st.elems {
226			if e.typ == res {
227				return F("(%v).%v", smith.rvalue(st), e.id)
228			}
229		}
230	}
231	return ""
232}
233
234func (smith *Smith) exprFunc(res *Type) string {
235	if !smith.satisfiesTrait(res, TraitGlobal) {
236		return ""
237	}
238	var f *Func
239	for _, f1 := range smith.packages[smith.curPackage].toplevFuncs {
240		if len(f1.rets) == 1 && f1.rets[0] == res {
241			f = f1
242			break
243		}
244	}
245	if f == nil {
246		f = smith.materializeFunc([]*Type{res})
247	}
248	if smith.rndBool() {
249		return F("%v(%v)", f.name, smith.fmtRvalueList(f.args))
250	} else {
251		var f0 *Func
252	loop:
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] {
258						continue loop
259					}
260				}
261				f0 = f1
262				break
263			}
264		}
265		if f0 == nil {
266			f0 = smith.materializeFunc(f.args)
267		}
268		return F("%v(%v(%v))", f.name, f0.name, smith.fmtRvalueList(f0.args))
269	}
270}
271
272func (smith *Smith) exprAddress(res *Type) string {
273	if res.class != ClassPointer {
274		return ""
275	}
276	if res.ktyp.class == ClassStruct && smith.rndBool() {
277		return F("&%v", res.ktyp.complexLiteral())
278	}
279	return F("(%v)(&(%v))", res.id, smith.lvalue(res.ktyp))
280}
281
282func (smith *Smith) exprDeref(res *Type) string {
283	return F("(*(%v))", smith.lvalue(pointerTo(res)))
284}
285
286func (smith *Smith) exprRecv(res *Type) string {
287	t := smith.chanOf(res)
288	return F("(<- %v)", smith.rvalue(t))
289}
290
291func (smith *Smith) exprArith(res *Type) string {
292	if res.class != ClassNumeric && res.class != ClassComplex {
293		return ""
294	}
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))
298}
299
300func (smith *Smith) exprEqual(res *Type) string {
301	if res != smith.boolType {
302		return ""
303	}
304	t := smith.atype(TraitComparable)
305	return F("(%v) %v (%v)", smith.rvalue(t), smith.choice("==", "!="), smith.rvalue(t))
306}
307
308func (smith *Smith) exprOrder(res *Type) string {
309	if res != smith.boolType {
310		return ""
311	}
312	t := smith.atype(TraitOrdered)
313	return F("(%v) %v (%v)", smith.rvalue(t), smith.choice("<", "<=", ">", ">="), smith.rvalue(t))
314
315}
316
317func (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))
320}
321
322func (smith *Smith) exprCallBuiltin(ret *Type) string {
323	switch fn := smith.choice("append", "cap", "complex", "copy", "imag", "len", "make", "new", "real", "recover"); fn {
324	case "append":
325		if ret.class != ClassSlice {
326			return ""
327		}
328		switch smith.choice("one", "two", "slice") {
329		case "one":
330			return F("%v(%v, %v)", fn, smith.rvalue(ret), smith.rvalue(ret.ktyp))
331		case "two":
332			return F("%v(%v, %v, %v)", fn, smith.rvalue(ret), smith.rvalue(ret.ktyp), smith.rvalue(ret.ktyp))
333		case "slice":
334			return F("%v(%v, %v...)", fn, smith.rvalue(ret), smith.rvalue(ret))
335		default:
336			panic("bad")
337		}
338	case "len", "cap":
339		if ret != smith.intType { // TODO: must be convertable
340			return ""
341		}
342		t := smith.atype(TraitLenCapable)
343		if (t.class == ClassString || t.class == ClassMap) && fn == "cap" {
344			return ""
345
346		}
347		return F("%v(%v)", fn, smith.rvalue(t))
348	case "copy":
349		if ret != smith.intType {
350			return ""
351		}
352		return F("%v", smith.exprCopySlice())
353	case "make":
354		if ret.class != ClassSlice && ret.class != ClassMap && ret.class != ClassChan {
355			return ""
356		}
357		cap := ""
358		if ret.class == ClassSlice {
359			if smith.rndBool() {
360				cap = F(", %v", smith.rvalue(smith.intType))
361			} else {
362				// Careful to not generate "len larger than cap".
363				cap = F(", 0, %v", smith.rvalue(smith.intType))
364			}
365		} else if smith.rndBool() {
366			cap = F(", %v", smith.rvalue(smith.intType))
367		}
368		return F("make(%v %v)", ret.id, cap)
369	case "new":
370		if ret.class != ClassPointer {
371			return ""
372		}
373		return F("new(%v)", ret.ktyp.id)
374	case "recover":
375		if ret != smith.efaceType {
376			return ""
377		}
378		return "recover()"
379	case "real", "imag":
380		if ret == smith.float32Type {
381			return F("real(%v)", smith.rvalue(smith.complex64Type))
382		}
383		if ret == smith.float64Type {
384			return F("real(%v)", smith.rvalue(smith.complex128Type))
385		}
386		return ""
387	case "complex":
388		if ret == smith.complex64Type {
389			return F("complex(%v, %v)", smith.rvalue(smith.float32Type), smith.rvalue(smith.float32Type))
390		}
391		if ret == smith.complex128Type {
392			return F("complex(%v, %v)", smith.rvalue(smith.float64Type), smith.rvalue(smith.float64Type))
393		}
394		return ""
395	default:
396		panic("bad")
397	}
398}
399
400func (smith *Smith) exprCopySlice() string {
401	if smith.rndBool() {
402		t := smith.atype(ClassSlice)
403		return F("copy(%v, %v)", smith.rvalue(t), smith.rvalue(t))
404	} else {
405		return F("copy(%v, %v)", smith.rvalue(smith.sliceOf(smith.byteType)), smith.rvalue(smith.stringType))
406	}
407}
408
409func (smith *Smith) exprSlice(ret *Type) string {
410	if ret.class != ClassSlice {
411		return ""
412	}
413	i0 := ""
414	if smith.rndBool() {
415		i0 = smith.nonconstRvalue(smith.intType)
416	}
417	i2 := ""
418	if smith.rndBool() {
419		i2 = ":" + smith.nonconstRvalue(smith.intType)
420	}
421	i1 := ":"
422	if smith.rndBool() || i2 != "" {
423		i1 = ":" + smith.nonconstRvalue(smith.intType)
424	}
425	return F("(%v)[%v%v%v]", smith.rvalue(ret), i0, i1, i2)
426}
427
428func (smith *Smith) exprIndexSlice(ret *Type) string {
429	return F("(%v)[%v]", smith.rvalue(smith.sliceOf(ret)), smith.nonconstRvalue(smith.intType))
430}
431
432func (smith *Smith) exprIndexString(ret *Type) string {
433	if ret != smith.byteType {
434		return ""
435	}
436	return F("(%v)[%v]", smith.rvalue(smith.stringType), smith.nonconstRvalue(smith.intType))
437}
438
439func (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))
442}
443
444func (smith *Smith) exprIndexMap(ret *Type) string {
445	// TODO: figure out something better
446	for i := 0; i < 10; i++ {
447		t := smith.atype(ClassMap)
448		if t.vtyp == ret {
449			return F("(%v)[%v]", smith.rvalue(t), smith.rvalue(t.ktyp))
450		}
451	}
452	return ""
453}
454
455func (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("", ","))
458	}
459	if ret.class == ClassComplex {
460		return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.atype(ClassComplex)), smith.choice("", ","))
461	}
462	if ret == smith.stringType {
463		switch smith.choice("int", "byteSlice", "runeSlice") {
464		case "int":
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("", ","))
468		case "byteSlice":
469			return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.sliceOf(smith.byteType)), smith.choice("", ","))
470		case "runeSlice":
471			return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.sliceOf(smith.runeType)), smith.choice("", ","))
472		default:
473			panic("bad")
474		}
475	}
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("", ","))
478	}
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"
482	return ""
483}
484