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