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 * declaration.go 12 * 13 * Created on Apr 01, 2017 14 * Author Massimiliano Ghilardi 15 */ 16 17package fast 18 19import ( 20 "go/ast" 21 "go/token" 22 r "reflect" 23 24 "github.com/cosmos72/gomacro/base/reflect" 25 26 "github.com/cosmos72/gomacro/base/strings" 27 28 "github.com/cosmos72/gomacro/base" 29 xr "github.com/cosmos72/gomacro/xreflect" 30) 31 32// Decl compiles a constant, variable, function or type declaration - or an import 33func (c *Comp) Decl(node ast.Decl) { 34 if node != nil { 35 c.Pos = node.Pos() 36 } 37 switch node := node.(type) { 38 case *ast.GenDecl: 39 c.GenDecl(node) 40 case *ast.FuncDecl: 41 c.DeclFunc(node) 42 default: 43 c.Errorf("unsupported declaration, expecting <*ast.GenDecl> or <*ast.FuncDecl>, found: %v <%v>", node, r.TypeOf(node)) 44 } 45} 46 47// GenDecl compiles a constant, variable or type declaration - or an import 48func (c *Comp) GenDecl(node *ast.GenDecl) { 49 switch node.Tok { 50 case token.IMPORT: 51 for _, decl := range node.Specs { 52 c.Import(decl) 53 } 54 case token.CONST: 55 var defaultType ast.Expr 56 var defaultExprs []ast.Expr 57 // https://go-review.googlesource.com/c/go/+/71750 58 // states "each block has its own version of iota" 59 // which is also implied, although somewhat subtly, 60 // by the latest definition of iota in Go language specs. 61 // 62 // So declare iota in the top scope, but restore the original bind after the const declarations, 63 // because an in-progress outer const declaration may have a current value for it. 64 top := c.TopComp() 65 defer top.endIota(top.beginIota()) 66 for i, decl := range node.Specs { 67 top.setIota(i) 68 c.DeclConsts(decl, defaultType, defaultExprs) 69 if valueSpec, ok := decl.(*ast.ValueSpec); ok && valueSpec.Values != nil { 70 defaultType = valueSpec.Type 71 defaultExprs = valueSpec.Values 72 } 73 } 74 case token.TYPE: 75 for _, decl := range node.Specs { 76 c.DeclType(decl) 77 } 78 case token.VAR: 79 for _, decl := range node.Specs { 80 c.DeclVars(decl) 81 } 82 case token.PACKAGE: 83 /* 84 modified parser converts 'package foo' to: 85 86 ast.GenDecl{ 87 Tok: token.PACKAGE, 88 Specs: []ast.Spec{ 89 &ast.ValueSpec{ 90 Values: []ast.Expr{ 91 &ast.BasicLit{ 92 Kind: token.String, 93 Value: "path/to/package", 94 }, 95 }, 96 }, 97 }, 98 } 99 */ 100 if len(node.Specs) == 1 { 101 if decl, ok := node.Specs[0].(*ast.ValueSpec); ok { 102 if len(decl.Values) == 1 { 103 if lit, ok := decl.Values[0].(*ast.BasicLit); ok { 104 if lit.Kind == token.STRING && (lit.Value == c.Name || strings.MaybeUnescapeString(lit.Value) == c.Path) { 105 break 106 } 107 } 108 // c.changePackage(name) 109 c.Debugf("cannot switch package from fast.Comp.Compile(), use Interp.ChangePackage() instead: %v // %T", node, node) 110 } 111 } 112 } 113 c.Errorf("unsupported package syntax, expecting a single package name, found: %v // %T", node, node) 114 default: 115 c.Errorf("unsupported declaration kind, expecting token.IMPORT, token.PACKAGE, token.CONST, token.TYPE or token.VAR, found %v: %v // %T", 116 node.Tok, node, node) 117 } 118} 119 120// DeclConsts compiles a set of constant declarations 121func (c *Comp) DeclConsts(node ast.Spec, defaultType ast.Expr, defaultExprs []ast.Expr) { 122 c.Pos = node.Pos() 123 switch node := node.(type) { 124 case *ast.ValueSpec: 125 if node.Type != nil || node.Values != nil { 126 defaultType = node.Type 127 defaultExprs = node.Values 128 } 129 names, t, inits := c.prepareDeclConstsOrVars(toStrings(node.Names), defaultType, defaultExprs) 130 c.DeclConsts0(names, t, inits) 131 default: 132 c.Errorf("unsupported constant declaration: expecting <*ast.ValueSpec>, found: %v <%v>", node, r.TypeOf(node)) 133 } 134} 135 136// DeclVars compiles a set of variable declarations i.e. "var x1, x2... [type] = expr1, expr2..." 137func (c *Comp) DeclVars(node ast.Spec) { 138 c.Pos = node.Pos() 139 switch node := node.(type) { 140 case *ast.ValueSpec: 141 names, t, inits := c.prepareDeclConstsOrVars(toStrings(node.Names), node.Type, node.Values) 142 c.DeclVars0(names, t, inits, toPos(node.Names)) 143 default: 144 c.Errorf("unsupported variable declaration: expecting <*ast.ValueSpec>, found: %v <%v>", node, r.TypeOf(node)) 145 } 146} 147 148// DeclVarsShort compiles a set of variable short declarations i.e. "x1, x2... := expr1, expr2..." 149func (c *Comp) DeclVarsShort(lhs []ast.Expr, rhs []ast.Expr) { 150 n := len(lhs) 151 if n == 0 { 152 return 153 } 154 names := make([]string, n) 155 pos := make([]token.Pos, n) 156 for i := range lhs { 157 if ident, ok := lhs[i].(*ast.Ident); ok { 158 names[i] = ident.Name 159 pos[i] = ident.NamePos 160 } else { 161 c.Errorf("non-name %v on left side of :=", lhs[i]) 162 } 163 } 164 _, t, inits := c.prepareDeclConstsOrVars(names, nil, rhs) 165 c.DeclVars0(names, t, inits, pos) 166} 167 168func toStrings(idents []*ast.Ident) []string { 169 n := len(idents) 170 names := make([]string, n) 171 for i, ident := range idents { 172 names[i] = ident.Name 173 } 174 return names 175} 176 177func toPos(idents []*ast.Ident) []token.Pos { 178 n := len(idents) 179 pos := make([]token.Pos, n) 180 for i, ident := range idents { 181 pos[i] = ident.NamePos 182 } 183 return pos 184} 185 186func (c *Comp) prepareDeclConstsOrVars(names []string, typ ast.Expr, exprs []ast.Expr) (names_out []string, t xr.Type, inits []*Expr) { 187 n := len(names) 188 if typ != nil { 189 t = c.Type(typ) 190 } 191 if exprs != nil { 192 inits = c.ExprsMultipleValues(exprs, n) 193 } 194 return names, t, inits 195} 196 197func (c *Comp) DeclConsts0(names []string, t xr.Type, inits []*Expr) { 198 n := len(names) 199 if inits == nil { 200 c.Errorf("constants without initialization: %v", names) 201 } else if len(inits) != n { 202 c.Errorf("cannot declare %d constants with %d initializers: %v", n, len(inits), names) 203 } 204 for i, name := range names { 205 init := inits[i] 206 if !init.Const() { 207 c.Errorf("const initializer for %q is not a constant", name) 208 } 209 c.DeclConst0(name, t, init.Value) 210 } 211} 212 213// DeclVars0 compiles a set of variable declarations 214func (c *Comp) DeclVars0(names []string, t xr.Type, inits []*Expr, pos []token.Pos) { 215 n := len(names) 216 ni := len(inits) 217 if ni == 0 || ni == n { 218 npos := len(pos) 219 for i, name := range names { 220 var init *Expr 221 if i < ni { 222 init = inits[i] 223 } 224 if i < npos { 225 c.Pos = pos[i] 226 } 227 c.DeclVar0(name, t, init) 228 } 229 } else if ni == 1 && n > 1 { 230 c.DeclMultiVar0(names, t, inits[0], pos) 231 } else { 232 c.Errorf("cannot declare %d variables from %d expressions: %v", n, ni, names) 233 } 234} 235 236// DeclConst0 compiles a constant declaration 237func (c *Comp) DeclConst0(name string, t xr.Type, value I) { 238 if !isLiteral(value) { 239 c.Errorf("const initializer for %q is not a constant: %v <%T>", name, value, value) 240 return 241 } 242 lit := c.litValue(value) 243 if t == nil { 244 t = lit.Type 245 } else { 246 value = lit.ConstTo(t) 247 } 248 bind := c.NewBind(name, ConstBind, t) 249 bind.Value = value // c.Binds[] is a map[string]*Bind => changes to *Bind propagate to the map 250} 251 252// NewFuncBind reserves space for a subsequent function declaration 253func (c *Comp) NewFuncBind(name string, t xr.Type) *Bind { 254 bind := c.NewBind(name, FuncBind, t) 255 if bind.Desc.Class() != FuncBind { 256 c.Errorf("internal error! Comp.NewBind(name=%q, class=FuncBind, type=%v) returned class=%v, expecting FuncBind", 257 name, t, bind.Desc.Class()) 258 } 259 return bind 260} 261 262// NewBind reserves space for a subsequent constant, function or variable declaration 263func (c *Comp) NewBind(name string, class BindClass, t xr.Type) *Bind { 264 if class == IntBind || class == VarBind { 265 // respect c.IntBindMax: if != 0, it's the maximum number of IntBind variables we can declare 266 // reason: see comment in IntBindMax definition. Shortly, Ent.Ints[] address was taken 267 // thus we cannot reallocate it => we must stop at its capacity, stored in c.IntBindMax 268 // by Interp.PrepareEnv() 269 if (c.IntBindMax == 0 || c.IntBindNum < c.IntBindMax) && 270 reflect.IsCategory(t.Kind(), r.Bool, r.Int, r.Uint, r.Float64, r.Complex128) { 271 // optimize booleans, integers, floats and complexes by storing them in Env.Ints []uint64 272 // note: complex128 occupies two uint64 slots! 273 class = IntBind 274 } else { 275 class = VarBind 276 } 277 } 278 return c.CompBinds.NewBind(&c.Output, name, class, t) 279} 280 281// NewBind reserves space for a subsequent constant, function or variable declaration 282func (c *CompBinds) NewBind(o *base.Output, name string, class BindClass, t xr.Type) *Bind { 283 // do NOT replace VarBind -> IntBind here: done by Comp.NewBind() above, 284 // and we are also invoked by Import.loadBinds() which needs to store 285 // booleans, integers, floats and complex64 into reflect.Value 286 // because such compiled global variables already exist at their own address 287 var index = NoIndex 288 if name == "_" { 289 // never store bindings for "_" in c.Binds 290 desc := class.MakeDescriptor(index) 291 return &Bind{Lit: Lit{Type: t}, Desc: desc, Name: name} 292 } 293 if c.Binds == nil { 294 c.Binds = make(map[string]*Bind) 295 } 296 if len(name) == 0 { 297 // unnamed function result, or unnamed switch/range/... expression 298 } else if bind := c.Binds[name]; bind != nil { 299 o.Warnf("redefined identifier: %v", name) 300 oldclass := bind.Desc.Class() 301 if (oldclass == IntBind) == (class == IntBind) { 302 // both are IntBind, or neither is. 303 if bind.Type.Kind() == r.Complex128 || t.Kind() != r.Complex128 { 304 // the new bind occupies fewer slots than the old one, 305 // or occupies the same number of slots 306 // => we can reuse the bind index 307 index = bind.Desc.Index() 308 } 309 } 310 } 311 // allocate a slot either in Binds or in IntBinds 312 switch class { 313 case ConstBind, TemplateFuncBind: 314 index = NoIndex 315 default: // case FuncBind, VarBind: 316 if index == NoIndex { 317 index = c.BindNum 318 c.BindNum++ 319 } 320 case IntBind: 321 if index == NoIndex { 322 index = c.IntBindNum 323 c.IntBindNum++ 324 if t.Kind() == r.Complex128 { 325 // complex128 occupies two slots 326 c.IntBindNum++ 327 } 328 } 329 } 330 desc := class.MakeDescriptor(index) 331 bind := &Bind{Lit: Lit{Type: t}, Desc: desc, Name: name} 332 if len(name) != 0 { 333 // skip unnamed function results, and unnamed switch/range/... expression 334 c.Binds[name] = bind 335 } 336 return bind 337} 338 339func (c *Comp) declUnnamedBind(init *Expr, o *Comp, upn int) *Symbol { 340 t := init.Type 341 bind := o.NewBind("", VarBind, t) 342 // c.Debugf("declUnnamedBind: allocated bind %v, upn = %d", bind, upn) 343 switch bind.Desc.Class() { 344 case IntBind: 345 // no difference between declaration and assignment for this class 346 va := bind.AsVar(upn, PlaceSettable) 347 c.SetVar(va, token.ASSIGN, init) 348 case VarBind: 349 // cannot use c.DeclVar0 because the variable is declared in o 350 // cannot use o.DeclVar0 because the initializer must be evaluated in c 351 // so initialize the binding manually 352 index := bind.Desc.Index() 353 f := init.AsX1() 354 conv := c.Converter(init.Type, t) 355 switch upn { 356 case 0: 357 c.append(func(env *Env) (Stmt, *Env) { 358 v := f(env) 359 if conv != nil { 360 v = conv(v) 361 } 362 // no need to create a settable reflect.Value 363 env.Vals[index] = v 364 env.IP++ 365 return env.Code[env.IP], env 366 }) 367 case 1: 368 c.append(func(env *Env) (Stmt, *Env) { 369 v := f(env) 370 if conv != nil { 371 v = conv(v) 372 } 373 // no need to create a settable reflect.Value 374 env.Outer.Vals[index] = v 375 env.IP++ 376 return env.Code[env.IP], env 377 }) 378 default: 379 c.append(func(env *Env) (Stmt, *Env) { 380 o := env 381 for i := 0; i < upn; i++ { 382 o = o.Outer 383 } 384 v := f(env) 385 if conv != nil { 386 v = conv(v) 387 } 388 // no need to create a settable reflect.Value 389 o.Vals[index] = v 390 env.IP++ 391 return env.Code[env.IP], env 392 }) 393 } 394 default: 395 c.Errorf("internal error! Comp.NewBind(name=%q, class=VarBind, type=%v) returned class=%v, expecting VarBind or IntBind", 396 "", t, bind.Desc.Class()) 397 return nil 398 } 399 return bind.AsSymbol(upn) 400} 401 402// DeclVar0 compiles a variable declaration. For caller's convenience, returns allocated Bind 403func (c *Comp) DeclVar0(name string, t xr.Type, init *Expr) *Bind { 404 if t == nil { 405 if init == nil { 406 c.Errorf("no value and no type, cannot declare : %v", name) 407 } 408 t = init.DefaultType() 409 if t == nil { 410 c.Errorf("cannot declare variable as untyped nil: %v", name) 411 } 412 n := init.NumOut() 413 if n == 0 { 414 c.Errorf("initializer returns no values, cannot declare variable: %v", name) 415 } else if n > 1 { 416 c.Warnf("initializer returns %d values, using only the first one to declare variable: %v", n, name) 417 } 418 } 419 bind := c.NewBind(name, VarBind, t) 420 desc := bind.Desc 421 switch desc.Class() { 422 default: 423 c.Errorf("internal error! Comp.NewBind(name=%q, class=VarBind, type=%v) returned class=%v, expecting VarBind or IntBind", 424 name, t, desc.Class()) 425 return bind 426 case IntBind: 427 // no difference between declaration and assignment for these classes 428 if init == nil { 429 // no initializer... use the zero-value of t 430 init = c.exprValue(t, xr.Zero(t).Interface()) 431 } 432 va := bind.AsVar(0, PlaceSettable) 433 c.SetVar(va, token.ASSIGN, init) 434 case VarBind: 435 index := desc.Index() 436 if index == NoIndex && init != nil { 437 // assigning a constant or expression to _ 438 // only keep the expression side effects 439 c.append(init.AsStmt(c)) 440 return bind 441 } 442 // declaring a variable in Env.Binds[], we must create a settable and addressable reflect.Value 443 if init == nil { 444 // no initializer... use the zero-value of t 445 rtype := t.ReflectType() 446 c.append(func(env *Env) (Stmt, *Env) { 447 // base.Debugf("declaring %v", bind) 448 env.Vals[index] = r.New(rtype).Elem() 449 env.IP++ 450 return env.Code[env.IP], env 451 }) 452 return bind 453 } 454 if init.Const() { 455 init.ConstTo(t) // convert untyped constants, check typed constants 456 } 457 fun := init.AsX1() // AsX1() panics if init.NumOut() == 0, warns if init.NumOut() > 1 458 tfun := init.Out(0) 459 if tfun == nil || (!tfun.IdenticalTo(t) && !tfun.AssignableTo(t)) { 460 c.Errorf("cannot assign <%v> to <%v> in variable declaration: %v <%v>%s", tfun, t, name, t, interfaceMissingMethod(tfun, t)) 461 return bind 462 } 463 var ret func(env *Env) (Stmt, *Env) 464 conv := c.Converter(init.Type, t) 465 rtype := t.ReflectType() 466 // optimization: no need to wrap multiple-valued function into a single-value function 467 if f, ok := init.Fun.(func(*Env) (r.Value, []r.Value)); ok { 468 if conv != nil { 469 ret = func(env *Env) (Stmt, *Env) { 470 ret, _ := f(env) 471 place := r.New(rtype).Elem() 472 place.Set(conv(ret)) 473 env.Vals[index] = place 474 env.IP++ 475 return env.Code[env.IP], env 476 } 477 } else { 478 ret = func(env *Env) (Stmt, *Env) { 479 ret, _ := f(env) 480 place := r.New(rtype).Elem() 481 place.Set(ret) 482 env.Vals[index] = place 483 env.IP++ 484 return env.Code[env.IP], env 485 } 486 } 487 } else { 488 if conv != nil { 489 ret = func(env *Env) (Stmt, *Env) { 490 ret := fun(env) 491 place := r.New(rtype).Elem() 492 place.Set(conv(ret)) 493 env.Vals[index] = place 494 env.IP++ 495 return env.Code[env.IP], env 496 } 497 } else { 498 ret = func(env *Env) (Stmt, *Env) { 499 ret := fun(env) 500 place := r.New(rtype).Elem() 501 place.Set(ret) 502 env.Vals[index] = place 503 env.IP++ 504 return env.Code[env.IP], env 505 } 506 } 507 } 508 c.append(ret) 509 } 510 return bind 511} 512 513// DeclBindRuntimeValue compiles a variable, function or constant declaration with a reflect.Value passed at runtime 514func (c *Comp) DeclBindRuntimeValue(bind *Bind) func(*Env, r.Value) { 515 desc := bind.Desc 516 index := desc.Index() 517 if index == NoIndex { 518 return nil 519 } 520 t := bind.Type 521 rtype := t.ReflectType() 522 switch desc.Class() { 523 default: 524 c.Errorf("cannot declare a %s with a value passed at runtime: %v <%v>", desc.Class(), bind.Name, t) 525 return nil 526 case FuncBind: 527 // declaring a function in Env.Binds[], the reflect.Value must not be addressable or settable 528 return func(env *Env, v r.Value) { 529 env.Vals[index] = convert(v, rtype) 530 } 531 case VarBind: 532 // declaring a variable in Env.Binds[], we must create a settable and addressable reflect.Value 533 return func(env *Env, v r.Value) { 534 place := r.New(rtype).Elem() 535 if v.Type() != rtype { 536 v = convert(v, rtype) 537 } 538 place.Set(v) 539 env.Vals[index] = place 540 } 541 case IntBind: 542 // no difference between declaration and assignment for IntBind 543 return c.varSetValue(bind.AsVar(0, PlaceSettable)) 544 } 545} 546 547// DeclMultiVar0 compiles multiple variable declarations from a single multi-valued expression 548func (c *Comp) DeclMultiVar0(names []string, t xr.Type, init *Expr, pos []token.Pos) { 549 if t == nil { 550 if init == nil { 551 c.Errorf("no value and no type, cannot declare variables: %v", names) 552 } 553 } 554 n := len(names) 555 npos := len(pos) 556 if n == 1 { 557 if npos != 0 { 558 c.Pos = pos[0] 559 } 560 c.DeclVar0(names[0], t, init) 561 return 562 } 563 ni := init.NumOut() 564 if ni < n { 565 c.Errorf("cannot declare %d variables from expression returning %d values: %v", n, ni, names) 566 } else if ni > n { 567 c.Warnf("declaring %d variables from expression returning %d values: %v", n, ni, names) 568 } 569 decls := make([]func(*Env, r.Value), n) 570 for i, name := range names { 571 ti := init.Out(i) 572 if t != nil && !t.IdenticalTo(ti) { 573 if ti != nil && !ti.AssignableTo(t) { 574 c.Errorf("cannot assign <%v> to <%v> in variable declaration: %v", ti, t, names) 575 return 576 } else { 577 ti = t // declared variable has type t, not the i-th type returned by multi-valued expression 578 } 579 } 580 bind := c.NewBind(name, VarBind, ti) 581 decls[i] = c.DeclBindRuntimeValue(bind) 582 } 583 fun := init.AsXV(COptDefaults) 584 if npos != 0 { 585 c.Pos = pos[0] 586 } 587 c.append(func(env *Env) (Stmt, *Env) { 588 // call the multi-valued function. we know ni > 1, so just use the []r.Value 589 _, rets := fun(env) 590 591 // declare and assign the variables one by one. we know n <= ni 592 for i, decl := range decls { 593 if decl != nil { 594 decl(env, rets[i]) 595 } 596 } 597 env.IP++ 598 return env.Code[env.IP], env 599 }) 600} 601 602// DeclFunc0 compiles a function declaration. For caller's convenience, returns allocated Bind 603func (c *Comp) DeclFunc0(name string, fun I) *Bind { 604 funv := r.ValueOf(fun) 605 t := c.TypeOf(fun) 606 if t.Kind() != r.Func { 607 c.Errorf("DeclFunc0(%s): expecting a function, received %v <%v>", name, fun, t) 608 } 609 bind := c.NewFuncBind(name, t) 610 index := bind.Desc.Index() 611 ret := func(env *Env) (Stmt, *Env) { 612 env.Vals[index] = funv 613 env.IP++ 614 return env.Code[env.IP], env 615 } 616 c.append(ret) 617 return bind 618} 619 620// DeclEnvFunc0 compiles a function declaration that accesses interpreter's Env. For caller's convenience, returns allocated Bind 621func (c *Comp) DeclEnvFunc0(name string, envfun Function) *Bind { 622 t := c.TypeOfFunction() 623 bind := c.NewBind(name, ConstBind, t) // not a regular function... its type is not accurate 624 bind.Value = envfun // c.Binds[] is a map[string]*Bind => changes to *Bind propagate to the map 625 return bind 626} 627 628// DeclBuiltin0 compiles a builtin function declaration. For caller's convenience, returns allocated Bind 629func (c *Comp) DeclBuiltin0(name string, builtin Builtin) *Bind { 630 t := c.TypeOfBuiltin() 631 bind := c.NewBind(name, ConstBind, t) // not a regular function... its type is not accurate 632 bind.Value = builtin // c.Binds[] is a map[string]*Bind => changes to *Bind propagate to the map 633 return bind 634} 635 636// replacement of reflect.TypeOf() that uses xreflect.TypeOf() 637func (c *Comp) TypeOf(val interface{}) xr.Type { 638 v := c.Universe 639 v.TryResolve = c.tryResolveForXtype 640 641 return v.TypeOf(val) 642} 643 644func (c *Comp) tryResolveForXtype(name, pkgpath string) xr.Type { 645 if c.FileComp().Path != pkgpath { 646 return nil 647 } 648 var t xr.Type 649 for c != nil && t == nil { 650 t = c.Types[name] 651 c = c.Outer 652 } 653 return t 654} 655