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