1/*
2 * gomacro - A Go interpreter with Lisp-like macros
3 *
4 * Copyright (C) 2017-2019 Massimiliano Ghilardi
5 *
6 *     This Source Code Form is subject to the terms of the Mozilla Public
7 *     License, v. 2.0. If a copy of the MPL was not distributed with this
8 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 *
11 * place_ops.go
12 *
13 *  Created on Apr 25, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package fast
18
19import (
20	"go/token"
21	r "reflect"
22
23	. "github.com/cosmos72/gomacro/base"
24	"github.com/cosmos72/gomacro/base/reflect"
25)
26
27
28:import (
29	"fmt"
30	"go/ast"
31	"go/token"
32	r "reflect"
33)
34
35
36:func upcasefirstbyte(str string) string {
37	if len(str) > 0 && str[0] >= 'a' && str[0] <= 'z' {
38		bytes := []byte(str)
39		bytes[0] -= 'a' - 'A'
40		return string(bytes)
41	}
42	return str
43}
44
45:func makeupcase(node ast.Node, name string) ast.Node {
46	// go/ast.SelectorExpr requires the foo in x.foo to be an *ast.Ident, cannot unquote there
47	kind := ~"{~,node . foo}
48	kind.Sel = &ast.Ident{Name: upcasefirstbyte(name)}
49	return kind
50}
51
52:func makekind(typ ast.Node) ast.Node {
53	name := EvalType(typ).Name()
54	return makeupcase(~'r, name)
55}
56
57:func makeunwrapvalue(node ast.Node, typ ast.Node) ast.Node {
58	name := EvalType(typ).Name()
59
60	// remove final digits from name()
61	// needed to convert Uint64 -> Uint etc. to calls reflect.Value.{tname}
62	for len(name) != 0 {
63		ch := name[len(name)-1]
64		if ch < '0' || ch > '9' {
65			break
66		}
67		name = name[0:len(name)-1]
68	}
69	if name == "uintptr" {
70		name = "uint" // use reflect.Value.Uint()
71	}
72
73	return makeupcase(node, name)
74}
75
76:func op_to_assign(op token.Token) token.Token {
77	switch op {
78	case token.ADD:
79		op = token.ADD_ASSIGN
80	case token.SUB:
81		op = token.SUB_ASSIGN
82	case token.MUL:
83		op = token.MUL_ASSIGN
84	case token.QUO:
85		op = token.QUO_ASSIGN
86	case token.REM:
87		op = token.REM_ASSIGN
88	case token.AND:
89		op = token.AND_ASSIGN
90	case token.OR:
91		op = token.OR_ASSIGN
92	case token.XOR:
93		op = token.XOR_ASSIGN
94	case token.SHL:
95		op = token.SHL_ASSIGN
96	case token.SHR:
97		op = token.SHR_ASSIGN
98	case token.AND_NOT:
99		op = token.AND_NOT_ASSIGN
100	default:
101		panic(fmt.Sprintf("cannot convert token %s to assignment token", op))
102	}
103	return op
104}
105
106:func fsetplace(opnode, typ, expr ast.Node) ast.Node {
107	// the return type of Eval() and EvalType() varies. better check early.
108	var t r.Type = EvalType(typ)
109	var bind ast.Node
110	var result *ast.BinaryExpr
111	op := Eval(opnode).(token.Token)
112	opset := op_to_assign(op)
113
114	switch t.Kind() {
115		case r.Int, r.Int8, r.Int16, r.Int32:
116			result = ~"{lhs.Int() + int64(~,expr)}
117			result.Op = op
118			bind = ~"{lhs.SetInt(~,result)}
119		case r.Int64:
120			result = ~"{lhs.Int() + ~,expr}
121			result.Op = op
122			bind = ~"{lhs.SetInt(~,result)}
123		case r.Uint, r.Uint8, r.Uint16, r.Uint32, r.Uintptr:
124			result = ~"{lhs.Uint() + uint64(~,expr)}
125			result.Op = op
126			bind = ~"{lhs.SetUint(~,result)}
127		case r.Uint64:
128			result = ~"{lhs.Uint() + ~,expr}
129			result.Op = op
130			bind = ~"{lhs.SetUint(~,result)}
131		case r.Float32:
132			result = ~"{lhs.Float() + float64(~,expr)}
133			result.Op = op
134			bind = ~"{lhs.SetFloat(~,result)}
135		case r.Float64:
136			result = ~"{lhs.Float() + ~,expr}
137			result.Op = op
138			bind = ~"{lhs.SetFloat(~,result)}
139		case r.Complex64:
140			result = ~"{lhs.Complex() + complex128(~,expr)}
141			result.Op = op
142			bind = ~"{lhs.SetComplex(~,result)}
143		case r.Complex128:
144			result = ~"{lhs.Complex() + ~,expr}
145			result.Op = op
146			bind = ~"{lhs.SetComplex(~,result)}
147		case r.String:
148			result = ~"{lhs.String() + ~,expr}
149			result.Op = op
150			bind = ~"{lhs.SetString(~,result)}
151		default:
152			panic("unimplemented: <" + t.String() + "> " + opset.String() + " expression" )
153	}
154
155	return ~"{
156		ret = func(env *Env) (Stmt, *Env) {
157			lhs := lhsfun(env)
158			~,bind
159			env.IP++
160			return env.Code[env.IP], env
161		}
162	}
163}
164
165:func fsetmap(opnode, typ, expr ast.Node) ast.Node {
166	// the return type of Eval() and EvalType() varies. better check early.
167	var t r.Type = EvalType(typ)
168	var curr *ast.BlockStmt
169	var result *ast.AssignStmt = ~"{result += ~,expr}
170	op := Eval(opnode).(token.Token)
171	opset := op_to_assign(op)
172	result.Tok = opset
173
174	switch t.Kind() {
175		case r.Int, r.Int8, r.Int16, r.Int32:
176			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = ~,typ(v.Int()) }}
177		case r.Int64:
178			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = v.Int() }}
179		case r.Uint, r.Uint8, r.Uint16, r.Uint32, r.Uintptr:
180			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = ~,typ(v.Uint()) }}
181		case r.Uint64:
182			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = v.Uint() }}
183		case r.Float32:
184			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = ~,typ(v.Float()) }}
185		case r.Float64:
186			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = v.Float() }}
187		case r.Complex64:
188			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = ~,typ(v.Complex()) }}
189		case r.Complex128:
190			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = v.Complex() }}
191		case r.String:
192			curr = ~"{var result ~,typ; if v := lhs.MapIndex(key); v != Nil { result = v.String() }}
193		default:
194			panic("unimplemented: <" + t.String() + "> " + opset.String() + " expression" )
195	}
196
197	return ~"{
198		ret = func(env *Env) (Stmt, *Env) {
199			lhs := lhsfun(env)
200			key := keyfun(env)
201			~,@curr
202			~,result
203			lhs.SetMapIndex(key, r.ValueOf(result))
204			env.IP++
205			return env.Code[env.IP], env
206		}
207	}
208}
209
210:macro setplace_const(opnode, typ ast.Node) ast.Node {
211	return fsetplace(opnode, typ, ~'val)
212}
213
214:macro setplace_expr(opnode, typ ast.Node) ast.Node {
215	return fsetplace(opnode, typ, ~'{fun(env)})
216}
217
218:macro setmap_const(opnode, typ ast.Node) ast.Node {
219	return fsetmap(opnode, typ, ~'val)
220}
221
222:macro setmap_expr(opnode, typ ast.Node) ast.Node {
223	return fsetmap(opnode, typ, ~'{fun(env)})
224}
225
226
227:func list_types(typelist []ast.Stmt) []ast.Node {
228	rets := make([]ast.Node, 0, len(typelist))
229	for _, typ := range typelist {
230		t := EvalType(typ)
231		if t == nil {
232			rets = append(rets, ~'nil)
233		} else if t.Kind() == r.Int {
234			rets = append(rets, ~'int, ~'int8, ~'int16, ~'int32, ~'int64)
235		} else if t.Kind() == r.Uint {
236			rets = append(rets, ~'uint, ~'uint8, ~'uint16, ~'uint32, ~'uint64, ~'uintptr)
237		} else if t.Kind() == r.Float64 {
238			rets = append(rets, ~'float32, ~'float64)
239		} else if t.Kind() == r.Complex128 {
240			rets = append(rets, ~'complex64, ~'complex128)
241		} else {
242			rets = append(rets, typ)
243		}
244	}
245	return rets
246}
247
248:macro setplaces_const(opnode, types ast.Node) ast.Node {
249	// separate cases for int8, uint16... not needed
250	typelist := types.(*ast.BlockStmt).List
251	caselist := make([]ast.Stmt, len(typelist))
252	for i, typ := range typelist {
253		if EvalType(typ) == nil {
254			caselist[i] = ~"{default: c.Errorf(`invalid operator %s= on <%v>`, ~,opnode, place.Type)}
255		} else {
256			kind := makekind(typ)
257			unwrap := makeunwrapvalue(~'v, typ)
258			caselist[i] = ~"{case ~,kind:
259				val := ~,unwrap ()
260				setplace_const; ~,opnode; ~,typ
261			}
262		}
263	}
264	// separate cases for int8, uint16... are needed
265	maptypelist := list_types(types.(*ast.BlockStmt).List)
266	mapcaselist := make([]ast.Stmt, len(maptypelist))
267	for i, typ := range maptypelist {
268		if EvalType(typ) == nil {
269			mapcaselist[i] = ~"{default: c.Errorf(`invalid operator %s= on <%v>`, ~,opnode, place.Type)}
270		} else {
271			kind := makekind(typ)
272			unwrap := makeunwrapvalue(~'v, typ)
273			mapcaselist[i] = ~"{case ~,kind:
274				val := ~,typ( ~,unwrap () )
275				setmap_const; ~,opnode; ~,typ
276			}
277		}
278	}
279	return ~"{
280		var ret Stmt
281		lhsfun := place.Fun
282		keyfun := place.MapKey
283		v := r.ValueOf(val)
284
285		if keyfun == nil {
286			switch reflect.Category(place.Type.Kind()) {
287				~,@caselist
288			}
289		} else {
290			switch place.Type.Kind() {
291				~,@mapcaselist
292			}
293		}
294		return ret
295	}
296}
297
298:macro setplaces_expr(opnode, types ast.Node) ast.Node {
299	typelist := list_types(types.(*ast.BlockStmt).List)
300	caselist := make([]ast.Stmt, len(typelist))
301	mapcaselist := make([]ast.Stmt, len(typelist))
302	for i, typ := range typelist {
303		if EvalType(typ) == nil {
304			caselist[i] = ~"{default: c.Errorf(`invalid operator %s= between <%v> and <%v>`, ~,opnode, place.Type, funTypeOut(fun))}
305			mapcaselist[i] = caselist[i]
306		} else {
307			caselist[i] = ~"{~typecase func(*Env) ~,typ:
308				setplace_expr; ~,opnode; ~,typ
309			}
310			mapcaselist[i] = ~"{~typecase func(*Env) ~,typ:
311				setmap_expr; ~,opnode; ~,typ
312			}
313		}
314	}
315	return ~"{
316		var ret Stmt
317		lhsfun := place.Fun
318		keyfun := place.MapKey
319		if keyfun == nil {
320			switch fun := fun.(type) {
321				~,@caselist
322			}
323		} else {
324			switch fun := fun.(type) {
325				~,@mapcaselist
326			}
327		}
328		return ret
329	}
330}
331
332// varAddConst compiles 'place += constant'
333func (c *Comp) placeAddConst(place *Place, val I) Stmt {
334	if isLiteralNumber(val, 0) || val == "" {
335		return c.placeForSideEffects(place)
336	}
337	setplaces_const; token.ADD; {int; uint; float64; complex128; string; nil}
338}
339
340// varAddExpr compiles 'place += expression'
341func (c *Comp) placeAddExpr(place *Place, fun I) Stmt {
342	setplaces_expr; token.ADD; {int; uint; float64; complex128; string; nil}
343}
344
345// placeSubConst compiles 'place -= constant'
346func (c *Comp) placeSubConst(place *Place, val I) Stmt {
347	if isLiteralNumber(val, 0) {
348		return c.placeForSideEffects(place)
349	}
350	setplaces_const; token.SUB; {int; uint; float64; complex128; nil}
351}
352
353// placeSubExpr compiles 'place -= expression'
354func (c *Comp) placeSubExpr(place *Place, fun I) Stmt {
355	setplaces_expr; token.SUB; {int; uint; float64; complex128; nil}
356}
357
358// placeMulConst compiles 'place *= constant'
359func (c *Comp) placeMulConst(place *Place, val I) Stmt {
360	if isLiteralNumber(val, 0) {
361		// place *= 0 is equivalent to place = 0
362		return c.placeSetZero(place)
363	} else if isLiteralNumber(val, 1) {
364		return c.placeForSideEffects(place)
365	}
366	setplaces_const; token.MUL; {int; uint; float64; complex128; nil}
367}
368
369// placeMulExpr compiles 'place *= expression'
370func (c *Comp) placeMulExpr(place *Place, fun I) Stmt {
371	setplaces_expr; token.MUL; {int; uint; float64; complex128; nil}
372}
373
374// placeQuoConst compiles 'place /= constant'
375func (c *Comp) placeQuoConst(place *Place, val I) Stmt {
376	if isLiteralNumber(val, 0) {
377		c.Errorf("division by %v <%v>", val, r.TypeOf(val))
378		return nil
379	} else if isLiteralNumber(val, 1) {
380		return c.placeForSideEffects(place)
381	}
382	if stmt := c.placeQuoPow2(place, val); stmt != nil {
383		return stmt
384	}
385	setplaces_const; token.QUO; {int; uint; float64; complex128; nil}
386}
387
388// placeQuoExpr compiles 'place /= expression'
389func (c *Comp) placeQuoExpr(place *Place, fun I) Stmt {
390	setplaces_expr; token.QUO; {int; uint; float64; complex128; nil}
391}
392
393// placeRemConst compiles 'place %= constant'
394func (c *Comp) placeRemConst(place *Place, val I) Stmt {
395	if reflect.IsCategory(place.Type.Kind(), r.Int, r.Uint) {
396		if isLiteralNumber(val, 0) {
397			c.Errorf("division by %v <%v>", val, place.Type)
398			return nil
399		} else if isLiteralNumber(val, 1) {
400			// place %= 1 is equivalent to place = 0
401			return c.placeSetZero(place)
402		}
403	}
404	setplaces_const; token.REM; {int; uint; nil}
405}
406
407// placeRemExpr compiles 'place %= expression'
408func (c *Comp) placeRemExpr(place *Place, fun I) Stmt {
409	setplaces_expr; token.REM; {int; uint; nil}
410}
411
412// placeAndConst compiles 'place &= constant'
413func (c *Comp) placeAndConst(place *Place, val I) Stmt {
414	if reflect.IsCategory(place.Type.Kind(), r.Int, r.Uint) {
415		if isLiteralNumber(val, -1) {
416			return c.placeForSideEffects(place)
417		} else if isLiteralNumber(val, 0) {
418			// place &= 0 is equivalent to place = 0
419			return c.placeSetZero(place)
420		}
421	}
422	setplaces_const; token.AND; {int; uint; nil}
423}
424
425// placeAndExpr compiles 'place &= expression'
426func (c *Comp) placeAndExpr(place *Place, fun I) Stmt {
427	setplaces_expr; token.AND; {int; uint; nil}
428}
429
430// placeOrConst compiles 'place |= constant'
431func (c *Comp) placeOrConst(place *Place, val I) Stmt {
432	if reflect.IsCategory(place.Type.Kind(), r.Int, r.Uint) && isLiteralNumber(val, 0) {
433		return c.placeForSideEffects(place)
434	}
435	setplaces_const; token.OR; {int; uint; nil}
436}
437
438// placeOrExpr compiles 'place |= expression'
439func (c *Comp) placeOrExpr(place *Place, fun I) Stmt {
440	setplaces_expr; token.OR; {int; uint; nil}
441}
442
443// placeXorConst compiles 'place ^= constant'
444func (c *Comp) placeXorConst(place *Place, val I) Stmt {
445	if reflect.IsCategory(place.Type.Kind(), r.Int, r.Uint) && isLiteralNumber(val, 0) {
446		return c.placeForSideEffects(place)
447	}
448	setplaces_const; token.XOR; {int; uint; nil}
449}
450
451// placeXorExpr compiles 'place ^= expression'
452func (c *Comp) placeXorExpr(place *Place, fun I) Stmt {
453	setplaces_expr; token.XOR; {int; uint; nil}
454}
455
456// placeAndnotConst compiles 'place &^= constant'
457func (c *Comp) placeAndnotConst(place *Place, val I) Stmt {
458	if reflect.IsCategory(place.Type.Kind(), r.Int, r.Uint) {
459		if isLiteralNumber(val, -1) {
460			// place &^= -1 is equivalent to place = 0
461			return c.placeSetZero(place)
462		} else if isLiteralNumber(val, 0) {
463			return c.placeForSideEffects(place)
464		}
465	}
466	setplaces_const; token.AND_NOT; {int; uint; nil}
467}
468
469// varAndnotExpr compiles 'place &^= expression'
470func (c *Comp) placeAndnotExpr(place *Place, fun I) Stmt {
471	setplaces_expr; token.AND_NOT; {int; uint; nil}
472}
473
474
475// setPlace compiles an assignment to a place:
476// 'place op constant' and 'place op expression'
477func (c *Comp) setPlace(place *Place, op token.Token, init *Expr) Stmt {
478	if place.IsVar() {
479		return c.setVar(&place.Var, op, init)
480	}
481	t := place.Type
482	if init.Const() {
483		init.ConstTo(t)
484	} else if init.Type == nil || !init.Type.AssignableTo(t) {
485		c.Errorf("incompatible types in assignment: <%v> %s <%v>", t, op, init.Type)
486		return nil
487	}
488	rt := t.ReflectType()
489	if init.Const() {
490		val := init.Value
491		v := r.ValueOf(val)
492		if v == None || v == Nil {
493			v = r.Zero(rt)
494			val = v.Interface()
495		} else if v.Type() != rt {
496			v = convert(v, rt)
497			val = v.Interface()
498		}
499		switch op {
500		case token.ASSIGN:
501			return c.placeSetConst(place, val)
502		case token.ADD, token.ADD_ASSIGN:
503			return c.placeAddConst(place, val)
504		case token.SUB, token.SUB_ASSIGN:
505			return c.placeSubConst(place, val)
506		case token.MUL, token.MUL_ASSIGN:
507			return c.placeMulConst(place, val)
508		case token.QUO, token.QUO_ASSIGN:
509			return c.placeQuoConst(place, val)
510		case token.REM, token.REM_ASSIGN:
511			return c.placeRemConst(place, val)
512		case token.AND, token.AND_ASSIGN:
513			return c.placeAndConst(place, val)
514		case token.OR, token.OR_ASSIGN:
515			return c.placeOrConst(place, val)
516		case token.XOR, token.XOR_ASSIGN:
517			return c.placeAndConst(place, val)
518		case token.AND_NOT, token.AND_NOT_ASSIGN:
519			return c.placeAndnotConst(place, val)
520		}
521	} else {
522		fun := init.Fun
523		switch op {
524		case token.ASSIGN:
525			return c.placeSetExpr(place, fun)
526		case token.ADD, token.ADD_ASSIGN:
527			return c.placeAddExpr(place, fun)
528		case token.SUB, token.SUB_ASSIGN:
529			return c.placeSubExpr(place, fun)
530		case token.MUL, token.MUL_ASSIGN:
531			return c.placeMulExpr(place, fun)
532		case token.QUO, token.QUO_ASSIGN:
533			return c.placeQuoExpr(place, fun)
534		case token.REM, token.REM_ASSIGN:
535			return c.placeRemExpr(place, fun)
536		case token.AND, token.AND_ASSIGN:
537			return c.placeAndExpr(place, fun)
538		case token.OR, token.OR_ASSIGN:
539			return c.placeOrExpr(place, fun)
540		case token.XOR, token.XOR_ASSIGN:
541			return c.placeAndExpr(place, fun)
542		case token.AND_NOT, token.AND_NOT_ASSIGN:
543			return c.placeAndnotExpr(place, fun)
544		}
545	}
546	c.Errorf("operator %s is not implemented", op)
547	return nil
548}
549
550
551