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 * var_setops.go
12 *
13 *  Created on Apr 09, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package fast
18
19import (	"fmt"
20	"go/token"
21	r "reflect"
22	"unsafe"
23
24	. "github.com/cosmos72/gomacro/base"
25	"github.com/cosmos72/gomacro/base/reflect"
26)
27
28:import (
29	"fmt"
30	"go/ast"
31	"go/token"
32	r "reflect"
33)
34
35:func upcasefirstbyte(str string) string {
36	if len(str) > 0 && str[0] >= 'a' && str[0] <= 'z' {
37		bytes := []byte(str)
38		bytes[0] -= 'a' - 'A'
39		return string(bytes)
40	}
41	return str
42}
43
44:func makekind(typ ast.Node) ast.Node {
45	t := EvalType(typ)
46	if t == nil {
47		return nil
48	}
49	// go/ast.SelectorExpr requires the foo in r.foo to be an *ast.Ident, cannot unquote there
50	kind := ~"{r . foo}
51	kind.Sel = &ast.Ident{Name: upcasefirstbyte(t.Name())}
52	return kind
53}
54
55
56:func convertvalue1(typ, val ast.Node) ast.Node {
57	var t r.Type = EvalType(typ)
58	if t == nil {
59		return val
60	}
61	// unwrap the result
62	tname := t.Name()
63	// remove final digits from t.Name()
64	// needed to convert Uint64 -> Uint etc. to calls reflect.Value.{tname}
65	for len(tname) != 0 {
66		ch := tname[len(tname)-1]
67		if ch < '0' || ch > '9' {
68			break
69		}
70		tname = tname[0:len(tname)-1]
71	}
72	if tname == "uintptr" {
73		tname = "uint" // use reflect.Value.Uint()
74	}
75	sel := ~"{~,val . foo} // we modify it destructively
76	sel.Sel = &ast.Ident{Name: upcasefirstbyte(tname)}
77
78	switch t.Kind() {
79	case r.Bool, r.Int64, r.Uint64, r.Float64, r.Complex128, r.String:
80		// result of reflect.Value.{tname} is already the correct type
81		val = ~"{~,sel ()}
82	default:
83		// convert int64, uint64... to the correct type
84		val = ~"{~,typ ( ~,sel () )}
85	}
86	return val
87}
88
89:func op_to_assign(op token.Token) token.Token {
90	switch op {
91	case token.ADD:
92		op = token.ADD_ASSIGN
93	case token.SUB:
94		op = token.SUB_ASSIGN
95	case token.MUL:
96		op = token.MUL_ASSIGN
97	case token.QUO:
98		op = token.QUO_ASSIGN
99	case token.REM:
100		op = token.REM_ASSIGN
101	case token.AND:
102		op = token.AND_ASSIGN
103	case token.OR:
104		op = token.OR_ASSIGN
105	case token.XOR:
106		op = token.XOR_ASSIGN
107	case token.SHL:
108		op = token.SHL_ASSIGN
109	case token.SHR:
110		op = token.SHR_ASSIGN
111	case token.AND_NOT:
112		op = token.AND_NOT_ASSIGN
113	default:
114		panic(fmt.Sprintf("cannot convert token %s to assignment token", op))
115	}
116	return op
117}
118
119:func fgetplace(depth, typ ast.Node) (/*loop*/ *ast.BlockStmt, /*env*/ ast.Node) {
120	// the return type of Eval() and EvalType() varies. better check early.
121	upn := Eval(depth).(int)
122	var t r.Type = EvalType(typ)
123	var env ast.Node
124	var loop *ast.BlockStmt
125
126	if upn >= 0 {
127		env = ~'{env}
128		for i := 0; i < upn; i++ {
129			env = ~"{~,env . Outer}
130		}
131	} else if upn == -2 {
132		env = ~'{env.FileEnv}
133	} else if upn == -3 {
134		env = ~'{env.FileEnv.Outer}
135	} else {
136		loop = ~'{
137			o := env.Outer.Outer.Outer
138			for i := 3; i < upn; i++ {
139				o = o.Outer
140			}
141		}
142		env = ~'o
143	}
144	return loop, env
145}
146
147:func fsetplace(opnode, depth, typ, expr, exprv ast.Node) ast.Node {
148	loop, env := fgetplace(depth, typ)
149	// the return type of Eval() and EvalType() varies. better check early.
150	var t r.Type = EvalType(typ)
151	op := Eval(opnode).(token.Token)
152	opset := op_to_assign(op)
153	var bind, cbind ast.Node
154
155	var assign *ast.AssignStmt = ~"{*(*~,typ)(unsafe.Pointer(& ~,env .Ints[index])) += ~,expr}
156	assign.Tok = opset
157	bind = assign
158
159	switch t.Kind() {
160		case r.Bool:
161			var result *ast.BinaryExpr = ~"{lhs.Bool() + ~,expr}
162			result.Op = op
163			cbind = ~"{lhs := ~,env . Vals[index]; lhs.SetBool(~,result)}
164		case r.Int, r.Int8, r.Int16, r.Int32, r.Int64:
165			var result *ast.BinaryExpr = ~"{lhs.Int() + int64(~,expr)}
166			result.Op = op
167			cbind = ~"{lhs := ~,env . Vals[index]; lhs.SetInt(~,result)}
168		case r.Uint, r.Uint8, r.Uint16, r.Uint32, r.Uint64, r.Uintptr:
169			var result *ast.BinaryExpr = ~"{lhs.Uint() + uint64(~,expr)}
170			result.Op = op
171			cbind = ~"{lhs := ~,env . Vals[index]; lhs.SetUint(~,result)}
172			if t.Kind() == r.Uint64 {
173				var assign *ast.AssignStmt = ~"{~,env . Ints[index] += ~,expr}
174				assign.Tok = opset
175				bind = assign
176			}
177		case r.Float32, r.Float64:
178			var result *ast.BinaryExpr = ~"{lhs.Float() + float64(~,expr)}
179			result.Op = op
180			cbind = ~"{lhs := ~,env . Vals[index]; lhs.SetFloat(~,result)}
181		case r.Complex64, r.Complex128:
182			var result *ast.BinaryExpr = ~"{lhs.Complex() + complex128(~,expr)}
183			result.Op = op
184			cbind = ~"{lhs := ~,env . Vals[index]; lhs.SetComplex(~,result)}
185		case r.String:
186			var result *ast.BinaryExpr = ~"{lhs.String() + ~,expr}
187			result.Op = op
188			bind = ~"{lhs := ~,env . Vals[index]; lhs.SetString(~,result)}
189	}
190
191	if cbind == nil {
192		return ~"{
193			ret = func(env *Env) (Stmt, *Env) {
194				~,@loop
195				~,bind
196				env.IP++
197				return env.Code[env.IP], env
198			}
199		}
200	}
201
202	return ~"{
203		if intbinds {
204			ret = func(env *Env) (Stmt, *Env) {
205				~,@loop
206				~,bind
207				env.IP++
208				return env.Code[env.IP], env
209			}
210		} else {
211			ret = func(env *Env) (Stmt, *Env) {
212				~,@loop
213				~,cbind
214				env.IP++
215				return env.Code[env.IP], env
216			}
217		}
218	}
219}
220
221:macro setplace_const(opnode, depth, typ ast.Node) ast.Node {
222	return fsetplace(opnode, depth, typ, ~'val, ~'v)
223}
224
225:macro setplace_expr(opnode, depth, typ ast.Node) ast.Node {
226	return fsetplace(opnode, depth, typ, ~'{fun(env)}, ~'{convert(fun(env), t)})
227}
228
229:macro setplace_depth_const(opnode, typ ast.Node) ast.Node {
230	return ~"{
231		switch upn {
232			case 0:         setplace_const; ~,opnode; 0; ~,typ
233			case 1:         setplace_const; ~,opnode; 1; ~,typ
234			case 2:         setplace_const; ~,opnode; 2; ~,typ
235			case c.Depth-1: setplace_const; ~,opnode;-2; ~,typ
236			default:        setplace_const; ~,opnode;-1; ~,typ
237		}
238	}
239}
240
241:macro setplace_depth_expr(opnode, typ ast.Node) ast.Node {
242	return ~"{
243		switch upn {
244			case 0:         setplace_expr; ~,opnode; 0; ~,typ
245			case 1:         setplace_expr; ~,opnode; 1; ~,typ
246			case 2:         setplace_expr; ~,opnode; 2; ~,typ
247			case c.Depth-1: setplace_expr; ~,opnode;-2; ~,typ
248			default:        setplace_expr; ~,opnode;-1; ~,typ
249		}
250	}
251}
252
253:func list_types(typelist []ast.Stmt) []ast.Node {
254	rets := make([]ast.Node, 0, len(typelist))
255	for _, typ := range typelist {
256		t := EvalType(typ)
257		if t == nil {
258			rets = append(rets, ~'nil)
259		} else if t.Kind() == r.Int {
260			rets = append(rets, ~'int, ~'int8, ~'int16, ~'int32, ~'int64)
261		} else if t.Kind() == r.Uint {
262			rets = append(rets, ~'uint, ~'uint8, ~'uint16, ~'uint32, ~'uint64, ~'uintptr)
263		} else if t.Kind() == r.Float64 {
264			rets = append(rets, ~'float32, ~'float64)
265		} else if t.Kind() == r.Complex128 {
266			rets = append(rets, ~'complex64, ~'complex128)
267		} else {
268			rets = append(rets, typ)
269		}
270	}
271	return rets
272}
273
274:macro setplaces_depth_const(opnode, types ast.Node) ast.Node {
275	typelist := list_types(types.(*ast.BlockStmt).List)
276	caselist := make([]ast.Stmt, len(typelist))
277	for i, typ := range typelist {
278		if EvalType(typ) == nil {
279			caselist[i] = ~"{default: c.Errorf(`invalid operator %s= on <%v>`, ~,opnode, t)}
280		} else {
281			kind := makekind(typ)
282			convertval := convertvalue1(typ, ~'{r.ValueOf(val)})
283			caselist[i] = ~"{case ~,kind: val := ~,convertval; setplace_depth_const; ~,opnode; ~,typ}
284		}
285	}
286	return ~"{
287		t := va.Type
288		upn := va.Upn
289		index := va.Desc.Index()
290		intbinds := va.Desc.Class() == IntBind
291		var ret Stmt
292		switch t.Kind() {
293			~,@caselist
294		}
295		return ret
296	}
297}
298
299:macro setplaces_depth_expr(opnode, types ast.Node) ast.Node {
300	typelist := list_types(types.(*ast.BlockStmt).List)
301	caselist := 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= on <%v>`, ~,opnode, t)}
305		} else {
306			caselist[i] = ~"{~typecase func(*Env) ~,typ: setplace_depth_expr; ~,opnode; ~,typ}
307		}
308	}
309	return ~"{
310		t := va.Type
311		upn := va.Upn
312		index := va.Desc.Index()
313		intbinds := va.Desc.Class() == IntBind
314		var ret Stmt
315		switch fun := fun.(type) {
316			~,@caselist
317		}
318		return ret
319	}
320}
321
322// varAddConst compiles 'variable += constant'
323func (c *Comp) varAddConst(va *Var, val I) Stmt {
324	if isLiteralNumber(val, 0) || val == "" {
325		return nil
326	}
327	setplaces_depth_const; token.ADD; {int; uint; float64; complex128; string; nil}
328}
329
330// varAddExpr compiles 'variable += expression'
331func (c *Comp) varAddExpr(va *Var, fun I) Stmt {
332	setplaces_depth_expr; token.ADD; {int; uint; float64; complex128; string; nil}
333}
334
335// varSubConst compiles 'variable -= constant'
336func (c *Comp) varSubConst(va *Var, val I) Stmt {
337	if isLiteralNumber(val, 0) {
338		return nil
339	}
340	setplaces_depth_const; token.SUB; {int; uint; float64; complex128; nil}
341}
342
343// varSubExpr compiles 'variable -= expression'
344func (c *Comp) varSubExpr(va *Var, fun I) Stmt {
345	setplaces_depth_expr; token.SUB; {int; uint; float64; complex128; nil}
346}
347
348// varMulConst compiles 'variable *= constant'
349func (c *Comp) varMulConst(va *Var, val I) Stmt {
350	if isLiteralNumber(val, 0) {
351		// variable *= 0 is equivalent to variable = 0
352		return c.varSetZero(va)
353	} else if isLiteralNumber(val, 1) {
354		return nil
355	}
356	setplaces_depth_const; token.MUL; {int; uint; float64; complex128; nil}
357}
358
359// varMulExpr compiles 'variable *= expression'
360func (c *Comp) varMulExpr(va *Var, fun I) Stmt {
361	setplaces_depth_expr; token.MUL; {int; uint; float64; complex128; nil}
362}
363
364:macro place_quopow2(depth, typ ast.Node) ast.Node {
365	var t r.Type = EvalType(typ)
366	loop, bind := fgetplace(depth, typ)
367
368	addr := ~"{(*~,typ)(unsafe.Pointer(& ~,bind .Ints[index]))}
369
370	return ~"{
371		y_1 := ~,typ(y - 1) // cannot overflow, y is the abs() value of a non-zero ~,typ
372		if ypositive {
373			ret = func(env *Env) (Stmt, *Env) {
374				~,@loop
375				addr := ~,addr
376				n := *addr
377				if n < 0 {
378					n += y_1
379				}
380				*addr = n >> shift
381				env.IP++
382				return env.Code[env.IP], env
383			}
384		} else {
385			ret = func(env *Env) (Stmt, *Env) {
386				~,@loop
387				addr := ~,addr
388				n := *addr
389				if n < 0 {
390					n += y_1
391				}
392				*addr = -(n >> shift)
393				env.IP++
394				return env.Code[env.IP], env
395			}
396		}
397	}
398}
399
400:macro place_quopow2_u(depth, typ ast.Node) ast.Node {
401	var t r.Type = EvalType(typ)
402	loop, bind := fgetplace(depth, typ)
403
404	if t.Kind() == r.Uint64 {
405		bind = ~"{~,bind . Ints[index]}
406	} else {
407		bind = ~"{*(*~,typ)(unsafe.Pointer(& ~,bind .Ints[index]))}
408	}
409	return ~"{
410		ret = func(env *Env) (Stmt, *Env) {
411			~,@loop
412			~,bind >>= shift
413			env.IP++
414			return env.Code[env.IP], env
415		}
416	}
417}
418
419:macro place_depth_quopow2(typ ast.Node) ast.Node {
420	return ~"{
421		switch upn {
422			case 0:			place_quopow2; 0; ~,typ
423			case 1:			place_quopow2; 1; ~,typ
424			case 2:			place_quopow2; 2; ~,typ
425			case c.Depth-1: place_quopow2;-2; ~,typ
426			default:        place_quopow2;-1; ~,typ
427		}
428	}
429}
430
431:macro place_depth_quopow2_u(typ ast.Node) ast.Node {
432	return ~"{
433		switch upn {
434			case 0:			place_quopow2_u; 0; ~,typ
435			case 1:			place_quopow2_u; 1; ~,typ
436			case 2:			place_quopow2_u; 2; ~,typ
437			case c.Depth-1: place_quopow2_u;-2; ~,typ
438			default:        place_quopow2_u;-1; ~,typ
439		}
440	}
441}
442
443// varQuoPow2 compiles 'variable /= constant-power-of-two'
444func (c *Comp) varQuoPow2(va *Var, val I) Stmt {
445	t := va.Type
446	if isLiteralNumber(val, 0) {
447		c.Errorf("division by %v <%v>", val, t)
448		return nil
449	} else if isLiteralNumber(val, 1) {
450		return nil // nothing to do
451	}
452	ypositive := true
453	yv := r.ValueOf(val)
454	var y uint64
455	switch reflect.Category(yv.Kind()) {
456	case r.Int:
457		sy := yv.Int()
458		if sy < 0 {
459			ypositive = false
460			y = uint64(-sy)
461		} else {
462			y = uint64(sy)
463		}
464	case r.Uint:
465		y = yv.Uint()
466	default:
467		// floating point or complex division
468		return nil
469	}
470	if !isPowerOfTwo(y) {
471		// division by multiplication and shift not implemented...
472		return nil
473	}
474	// attention: xe / (2**n) and xe >> n have different truncation rules for negative xe:
475	//    quotient / truncates toward zero
476	//    right shift >> truncates toward negative infinity
477	// see quoPow2() in binary_ops.go for more details
478	shift := integerLen(y) - 1
479	upn := va.Upn
480	index := va.Desc.Index()
481	var ret Stmt
482
483	switch t.Kind() {
484	case r.Int:     {place_depth_quopow2; int}
485	case r.Int8:    {place_depth_quopow2; int8}
486	case r.Int16:   {place_depth_quopow2; int16}
487	case r.Int32:   {place_depth_quopow2; int32}
488	case r.Int64:   {place_depth_quopow2; int64}
489	case r.Uint:    {place_depth_quopow2_u; uint}
490	case r.Uint8:   {place_depth_quopow2_u; uint8}
491	case r.Uint16:  {place_depth_quopow2_u; uint16}
492	case r.Uint32:  {place_depth_quopow2_u; uint32}
493	case r.Uint64:  {place_depth_quopow2_u; uint64}
494	case r.Uintptr: {place_depth_quopow2_u; uintptr}
495	}
496	return ret
497}
498
499// varQuoConst compiles 'variable /= constant'
500func (c *Comp) varQuoConst(va *Var, val I) Stmt {
501	if isLiteralNumber(val, 0) {
502		c.Errorf("division by %v <%T>", val, val)
503		return nil
504	} else if isLiteralNumber(val, 1) {
505		return nil
506	} else if isLiteralNumber(val, -1) {
507		return c.varMulConst(va, val)
508	}
509	if stmt := c.varQuoPow2(va, val); stmt != nil {
510		return stmt
511	}
512	setplaces_depth_const; token.QUO; {int; uint; float64; complex128; nil}
513}
514
515// varQuoExpr compiles 'variable /= expression'
516func (c *Comp) varQuoExpr(va *Var, fun I) Stmt {
517	setplaces_depth_expr; token.QUO; {int; uint; float64; complex128; nil}
518}
519
520// varRemConst compiles 'variable %= constant'
521func (c *Comp) varRemConst(va *Var, val I) Stmt {
522	t := va.Type
523	if reflect.IsCategory(t.Kind(), r.Int, r.Uint) {
524		if isLiteralNumber(val, 0) {
525			c.Errorf("division by %v <%v>", val, t)
526			return nil
527		} else if isLiteralNumber(val, 1) {
528			// variable %= 1 is equivalent to variable = 0
529			return c.varSetZero(va)
530		}
531	}
532	setplaces_depth_const; token.REM; {int; uint; nil}
533}
534
535// varRemExpr compiles 'variable %= expression'
536func (c *Comp) varRemExpr(va *Var, fun I) Stmt {
537	setplaces_depth_expr; token.REM; {int; uint; nil}
538}
539
540// varAndConst compiles 'variable &= constant'
541func (c *Comp) varAndConst(va *Var, val I) Stmt {
542	t := va.Type
543	if reflect.IsCategory(t.Kind(), r.Int, r.Uint) {
544		if isLiteralNumber(val, -1) {
545			return nil
546		} else if isLiteralNumber(val, 0) {
547			// variable &= 0 is equivalent to variable = 0
548			return c.varSetZero(va)
549		}
550	}
551	setplaces_depth_const; token.AND; {int; uint; nil}
552}
553
554// varAndExpr compiles 'variable &= expression'
555func (c *Comp) varAndExpr(va *Var, fun I) Stmt {
556	setplaces_depth_expr; token.AND; {int; uint; nil}
557}
558
559// varOrConst compiles 'variable |= constant'
560func (c *Comp) varOrConst(va *Var, val I) Stmt {
561	t := va.Type
562	if reflect.IsCategory(t.Kind(), r.Int, r.Uint) && isLiteralNumber(val, 0) {
563		return nil
564	}
565	setplaces_depth_const; token.OR; {int; uint; nil}
566}
567
568// varOrExpr compiles 'variable |= expression'
569func (c *Comp) varOrExpr(va *Var, fun I) Stmt {
570	setplaces_depth_expr; token.OR; {int; uint; nil}
571}
572
573// varXorConst compiles 'variable ^= constant'
574func (c *Comp) varXorConst(va *Var, val I) Stmt {
575	t := va.Type
576	if reflect.IsCategory(t.Kind(), r.Int, r.Uint) && isLiteralNumber(val, 0) {
577		return nil
578	}
579	setplaces_depth_const; token.XOR; {int; uint; nil}
580}
581
582// varXorExpr compiles 'variable ^= expression'
583func (c *Comp) varXorExpr(va *Var, fun I) Stmt {
584	setplaces_depth_expr; token.XOR; {int; uint; nil}
585}
586
587// varAndnotConst compiles 'variable &^= constant'
588func (c *Comp) varAndnotConst(va *Var, val I) Stmt {
589	t := va.Type
590	if reflect.IsCategory(t.Kind(), r.Int, r.Uint) {
591		if isLiteralNumber(val, -1) {
592			// variable &^= -1 is equivalent to variable = 0
593			return c.varSetZero(va)
594		} else if isLiteralNumber(val, 0) {
595			return nil
596		}
597	}
598	setplaces_depth_const; token.AND_NOT; {int; uint; nil}
599}
600
601// varAndnotExpr compiles 'variable &^= expression'
602func (c *Comp) varAndnotExpr(va *Var, fun I) Stmt {
603	setplaces_depth_expr; token.AND_NOT; {int; uint; nil}
604}
605
606
607// setVar compiles an assignment to a variable:
608// 'variable op constant' and 'variable op expression'
609// returns a compiled statement that executes the assignment
610func (c *Comp) setVar(va *Var, op token.Token, init *Expr) Stmt {
611	t := va.Type
612	var shift bool
613	var err interface{} = ""
614	switch op {
615	case token.SHL, token.SHL_ASSIGN, token.SHR, token.SHR_ASSIGN:
616		shift = true
617		if init.Untyped() {
618			init.ConstTo(c.TypeOfUint64())
619			err = nil
620		} else if init.Type == nil || reflect.Category(init.Type.Kind()) != r.Uint {
621			err = fmt.Sprintf("\n\treason: type %v is %v, expecting unsigned integer", init.Type, init.Type.Kind())
622		} else {
623			err = nil
624		}
625	default:
626		if init.Const() {
627			init.ConstTo(t)
628			err = nil
629		} else if init.Type == nil {
630			if op != token.ASSIGN {
631				err = fmt.Sprintf("\n\treason: invalid operation %s nil", op)
632			} else if !reflect.IsNillableKind(t.Kind()) {
633				err = fmt.Sprintf("\n\treason: cannot assign nil to %v", t)
634			}
635		} else if !init.Type.AssignableTo(t) {
636			err = interfaceMissingMethod(init.Type, t)
637		} else {
638			err = nil
639		}
640	}
641	if err != nil {
642		c.Errorf("incompatible types in assignment: %v %s %v%v", t, op, init.Type, err)
643		return nil
644	}
645	class := va.Desc.Class()
646	if class != VarBind && class != IntBind {
647		c.Errorf("invalid operator %s on %v", op, class)
648		return nil
649	}
650	index := va.Desc.Index()
651	if index == NoIndex {
652		if op != token.ASSIGN {
653			c.Errorf("invalid operator %s on _", op)
654		}
655		if init.Const() {
656			return nil
657		}
658		return init.AsStmt(c)
659	}
660	if init.Const() {
661		rt := t.ReflectType()
662		val := init.Value
663		v := r.ValueOf(val)
664		if v == None || v == Nil {
665			v = r.Zero(rt)
666			val = v.Interface()
667		} else if v.Type() != rt && !shift {
668			v = convert(v, rt)
669			val = v.Interface()
670		}
671		switch op {
672		case token.ASSIGN:
673			return c.varSetConst(va, val)
674		case token.ADD, token.ADD_ASSIGN:
675			return c.varAddConst(va, val)
676		case token.SUB, token.SUB_ASSIGN:
677			return c.varSubConst(va, val)
678		case token.MUL, token.MUL_ASSIGN:
679			return c.varMulConst(va, val)
680		case token.QUO, token.QUO_ASSIGN:
681			return c.varQuoConst(va, val)
682		case token.REM, token.REM_ASSIGN:
683			return c.varRemConst(va, val)
684		case token.AND, token.AND_ASSIGN:
685			return c.varAndConst(va, val)
686		case token.OR, token.OR_ASSIGN:
687			return c.varOrConst(va, val)
688		case token.XOR, token.XOR_ASSIGN:
689			return c.varXorConst(va, val)
690		case token.SHL, token.SHL_ASSIGN:
691			return c.varShlConst(va, val)
692		case token.SHR, token.SHR_ASSIGN:
693			return c.varShrConst(va, val)
694		case token.AND_NOT, token.AND_NOT_ASSIGN:
695			return c.varAndnotConst(va, val)
696		}
697	} else {
698		fun := init.Fun
699		switch op {
700		case token.ASSIGN:
701			return c.varSetExpr(va, init)
702		case token.ADD, token.ADD_ASSIGN:
703			return c.varAddExpr(va, fun)
704		case token.SUB, token.SUB_ASSIGN:
705			return c.varSubExpr(va, fun)
706		case token.MUL, token.MUL_ASSIGN:
707			return c.varMulExpr(va, fun)
708		case token.QUO, token.QUO_ASSIGN:
709			return c.varQuoExpr(va, fun)
710		case token.REM, token.REM_ASSIGN:
711			return c.varRemExpr(va, fun)
712		case token.AND, token.AND_ASSIGN:
713			return c.varAndExpr(va, fun)
714		case token.OR, token.OR_ASSIGN:
715			return c.varOrExpr(va, fun)
716		case token.XOR, token.XOR_ASSIGN:
717			return c.varXorExpr(va, fun)
718		case token.SHL, token.SHL_ASSIGN:
719			return c.varShlExpr(va, fun)
720		case token.SHR, token.SHR_ASSIGN:
721			return c.varShrExpr(va, fun)
722		case token.AND_NOT, token.AND_NOT_ASSIGN:
723			return c.varAndnotExpr(va, fun)
724		}
725	}
726	c.Errorf("invalid operator %s", op)
727	return nil
728}
729