diff --git a/codebuild.go b/codebuild.go index 19fc7218..87461a68 100644 --- a/codebuild.go +++ b/codebuild.go @@ -590,7 +590,7 @@ func (p *CodeBuilder) NewType(name string, pos ...token.Pos) *TypeDecl { if debugInstr { log.Println("NewType", name) } - return p.pkg.doNewType(p.current.scope, getPos(pos), name, nil, 0) + return p.typeDefs().NewType(name, pos...) } // AliasType func @@ -598,7 +598,7 @@ func (p *CodeBuilder) AliasType(name string, typ types.Type, pos ...token.Pos) * if debugInstr { log.Println("AliasType", name, typ) } - decl := p.pkg.doNewType(p.current.scope, getPos(pos), name, typ, 1) + decl := p.typeDefs().AliasType(name, typ, pos...) return decl.typ } @@ -607,7 +607,8 @@ func (p *CodeBuilder) NewConstStart(typ types.Type, names ...string) *CodeBuilde if debugInstr { log.Println("NewConstStart", names) } - return p.pkg.newValueDecl(nil, p.current.scope, token.NoPos, token.CONST, typ, names...).InitStart(p.pkg) + defs := p.valueDefs(token.CONST) + return p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.CONST, typ, names...).InitStart(p.pkg) } // NewVar func @@ -615,7 +616,8 @@ func (p *CodeBuilder) NewVar(typ types.Type, names ...string) *CodeBuilder { if debugInstr { log.Println("NewVar", names) } - p.pkg.newValueDecl(nil, p.current.scope, token.NoPos, token.VAR, typ, names...) + defs := p.valueDefs(token.VAR) + p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.VAR, typ, names...) return p } @@ -624,7 +626,8 @@ func (p *CodeBuilder) NewVarStart(typ types.Type, names ...string) *CodeBuilder if debugInstr { log.Println("NewVarStart", names) } - return p.pkg.newValueDecl(nil, p.current.scope, token.NoPos, token.VAR, typ, names...).InitStart(p.pkg) + defs := p.valueDefs(token.VAR) + return p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.VAR, typ, names...).InitStart(p.pkg) } // DefineVarStart func @@ -632,7 +635,8 @@ func (p *CodeBuilder) DefineVarStart(pos token.Pos, names ...string) *CodeBuilde if debugInstr { log.Println("DefineVarStart", names) } - return p.pkg.newValueDecl(nil, p.current.scope, pos, token.DEFINE, nil, names...).InitStart(p.pkg) + return p.pkg.newValueDecl( + ValueAt{}, p.current.scope, pos, token.DEFINE, nil, names...).InitStart(p.pkg) } // NewAutoVar func diff --git a/error_msg_test.go b/error_msg_test.go index 548f32da..1c81ad9d 100644 --- a/error_msg_test.go +++ b/error_msg_test.go @@ -297,7 +297,7 @@ func TestErrConst(t *testing.T) { codeErrorTest(t, "./foo.gop:2:9: a redeclared in this block\n\tprevious declaration at ./foo.gop:1:5", func(pkg *gox.Package) { pkg.NewVarStart(position(1, 5), nil, "a").Val(1).EndInit(1) - pkg.NewConstDecl(pkg.Types.Scope()). + pkg.NewConstDefs(pkg.Types.Scope()). New(func(cb *gox.CodeBuilder) int { cb.Val(2) return 1 @@ -306,7 +306,7 @@ func TestErrConst(t *testing.T) { }) codeErrorTest(t, "./foo.gop:2:9: extra expression in const declaration", func(pkg *gox.Package) { - pkg.NewConstDecl(pkg.Types.Scope()). + pkg.NewConstDefs(pkg.Types.Scope()). New(func(cb *gox.CodeBuilder) int { cb.Val(2) cb.Val(ctxRef(pkg, "iota")) @@ -316,7 +316,7 @@ func TestErrConst(t *testing.T) { }) codeErrorTest(t, "./foo.gop:2:9: missing value in const declaration", func(pkg *gox.Package) { - pkg.NewConstDecl(pkg.Types.Scope()). + pkg.NewConstDefs(pkg.Types.Scope()). New(func(cb *gox.CodeBuilder) int { cb.Val(2) cb.Val(ctxRef(pkg, "iota")) diff --git a/package_test.go b/package_test.go index 10e3dacb..1079bf85 100644 --- a/package_test.go +++ b/package_test.go @@ -601,7 +601,9 @@ func main() { func TestTypeDoc(t *testing.T) { pkg := newMainPackage() typ := types.NewStruct(nil, nil) - pkg.NewType("foo").SetComments(comment("\n//go:notinheap")).InitType(pkg, typ) + def := pkg.NewTypeDefs().SetComments(nil) + def.NewType("foo").SetComments(comment("\n//go:notinheap")).InitType(pkg, typ) + def.Complete() domTest(t, pkg, `package main //go:notinheap @@ -613,7 +615,8 @@ type foo struct { func TestDeleteType(t *testing.T) { pkg := newMainPackage() typ := types.NewStruct(nil, nil) - decl := pkg.NewType("foo") + def := pkg.NewTypeDefs() + decl := def.NewType("foo") if decl.State() != gox.TyStateUninited { t.Fatal("TypeDecl.State failed") } @@ -625,7 +628,12 @@ func TestDeleteType(t *testing.T) { if decl.State() != gox.TyStateDeleted { t.Fatal("TypeDecl.State failed") } + def.NewType("t").InitType(def.Pkg(), gox.TyByte) + def.NewType("bar").Delete() + def.Complete() domTest(t, pkg, `package main + +type t byte `) } @@ -666,11 +674,11 @@ func TestTypeCycleDef(t *testing.T) { foo.InitType(pkg, types.NewStruct(fields, nil)) domTest(t, pkg, `package main -type a = foo -type b = a type foo struct { p *b } +type a = foo +type b = a `) } @@ -1209,7 +1217,7 @@ func TestConstLenCap(t *testing.T) { func TestConstDecl(t *testing.T) { pkg := newMainPackage() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg) - pkg.NewConstDefs(pkg.CB().Scope()).New(func(cb *gox.CodeBuilder) int { + pkg.NewConstDefs(pkg.CB().Scope()).SetComments(nil).New(func(cb *gox.CodeBuilder) int { cb.Val(1).Val(2).BinaryOp(token.ADD) return 1 }, 0, token.NoPos, nil, "n") @@ -1230,7 +1238,7 @@ func main() { func TestConstDecl2(t *testing.T) { pkg := newMainPackage() - pkg.NewConstDecl(pkg.Types.Scope()). + pkg.NewConstDefs(pkg.Types.Scope()). New(func(cb *gox.CodeBuilder) int { cb.Val(ctxRef(pkg, "iota")) return 1 @@ -1264,7 +1272,7 @@ const ( func TestConstDecl3(t *testing.T) { pkg := newMainPackage() - pkg.NewConstDecl(pkg.Types.Scope()). + pkg.NewConstDefs(pkg.Types.Scope()). New(func(cb *gox.CodeBuilder) int { cb.Val(1).Val(ctxRef(pkg, "iota")).BinaryOp(token.SHL) return 1 @@ -1291,7 +1299,7 @@ func TestDeleteVarDecl(t *testing.T) { pkg := newMainPackage() pkg.SetRedeclarable(true) scope := pkg.CB().Scope() - defs := pkg.NewVarDefs(scope) + defs := pkg.NewVarDefs(scope).SetComments(nil) decl := defs.New(token.NoPos, types.Typ[types.Int], "a", "b") defs.New(token.NoPos, types.Typ[types.String], "c") defs.New(token.NoPos, types.Typ[types.String], "s") diff --git a/type_var_and_const.go b/type_var_and_const.go index 331a0e48..a6e361a6 100644 --- a/type_var_and_const.go +++ b/type_var_and_const.go @@ -48,14 +48,13 @@ const ( // TypeDecl type type TypeDecl struct { - typ *types.Named - decl *ast.GenDecl - scope *types.Scope + typ *types.Named + spec *ast.TypeSpec } // SetComments sets associated documentation. func (p *TypeDecl) SetComments(doc *ast.CommentGroup) *TypeDecl { - p.decl.Doc = doc + p.spec.Doc = doc return p } @@ -69,8 +68,9 @@ func (p *TypeDecl) Type() *types.Named { // If InitType is called (but not deleted), it returns TyStateInited. // Otherwise it returns TyStateUninited. func (p *TypeDecl) State() TyState { - if spec := p.decl.Specs; len(spec) > 0 { - if spec[0].(*ast.TypeSpec).Type != nil { + spec := p.spec + if spec.Name != nil { + if spec.Type != nil { return TyStateInited } return TyStateUninited @@ -81,13 +81,13 @@ func (p *TypeDecl) State() TyState { // Delete deletes this type. // NOTE: It panics if you call InitType after Delete. func (p *TypeDecl) Delete() { - p.decl.Specs = p.decl.Specs[:0] + p.spec.Name = nil } // Inited checkes if InitType is called or not. // Will panic if this type is deleted (please use State to check). func (p *TypeDecl) Inited() bool { - return p.decl.Specs[0].(*ast.TypeSpec).Type != nil + return p.spec.Type != nil } // InitType initializes a uncompleted type. @@ -95,7 +95,7 @@ func (p *TypeDecl) InitType(pkg *Package, typ types.Type, tparams ...*TypeParam) if debugInstr { log.Println("InitType", p.typ.Obj().Name(), typ) } - spec := p.decl.Specs[0].(*ast.TypeSpec) + spec := p.spec if spec.Type != nil { log.Panicln("TODO: type already defined -", typ) } @@ -106,25 +106,98 @@ func (p *TypeDecl) InitType(pkg *Package, typ types.Type, tparams ...*TypeParam) } setTypeParams(pkg, p.typ, spec, tparams) spec.Type = toType(pkg, typ) - pkg.appendGenDecl(p.scope, p.decl) return p.typ } -// AliasType gives a specified type with a new name -func (p *Package) AliasType(name string, typ types.Type, pos ...token.Pos) *types.Named { +// ---------------------------------------------------------------------------- + +// TypeDefs represents a type declaration block. +type TypeDefs struct { + decl *ast.GenDecl + scope *types.Scope + pkg *Package +} + +// Pkg returns the package instance. +func (p *TypeDefs) Pkg() *Package { + return p.pkg +} + +// SetComments sets associated documentation. +func (p *TypeDefs) SetComments(doc *ast.CommentGroup) *TypeDefs { + p.decl.Doc = doc + return p +} + +// NewType creates a new type (which need to call InitType later). +func (p *TypeDefs) NewType(name string, pos ...token.Pos) *TypeDecl { + if debugInstr { + log.Println("NewType", name) + } + return p.pkg.doNewType(p, getPos(pos), name, nil, 0) +} + +// AliasType gives a specified type with a new name. +func (p *TypeDefs) AliasType(name string, typ types.Type, pos ...token.Pos) *TypeDecl { if debugInstr { log.Println("AliasType", name, typ) } - decl := p.doNewType(p.Types.Scope(), getPos(pos), name, typ, 1) + return p.pkg.doNewType(p, getPos(pos), name, typ, 1) +} + +// Complete checks type declarations & marks completed. +func (p *TypeDefs) Complete() { + decl := p.decl + specs := decl.Specs + if len(specs) == 1 && decl.Doc == nil { + if spec := specs[0].(*ast.TypeSpec); spec.Doc != nil { + decl.Doc, spec.Doc = spec.Doc, nil + } + } + for i, spec := range specs { + v := spec.(*ast.TypeSpec) + if v.Name == nil || v.Type == nil { + for j := i + 1; j < len(specs); j++ { + v = specs[j].(*ast.TypeSpec) + if v.Name != nil && v.Type != nil { + specs[i] = v + i++ + } + } + decl.Specs = specs[:i] + return + } + } +} + +// ---------------------------------------------------------------------------- + +// AliasType gives a specified type with a new name. +// +// Deprecated: use NewTypeDefs instead. +func (p *Package) AliasType(name string, typ types.Type, pos ...token.Pos) *types.Named { + decl := p.NewTypeDefs().AliasType(name, typ, pos...) return decl.typ } // NewType creates a new type (which need to call InitType later). +// +// Deprecated: use NewTypeDefs instead. func (p *Package) NewType(name string, pos ...token.Pos) *TypeDecl { - if debugInstr { - log.Println("NewType", name) - } - return p.doNewType(p.Types.Scope(), getPos(pos), name, nil, 0) + return p.NewTypeDefs().NewType(name, pos...) +} + +// NewTypeDefs starts a type declaration block. +func (p *Package) NewTypeDefs() *TypeDefs { + decl := &ast.GenDecl{Tok: token.TYPE} + p.file.decls = append(p.file.decls, decl) + return &TypeDefs{decl: decl, scope: p.Types.Scope(), pkg: p} +} + +func (p *CodeBuilder) typeDefs() *TypeDefs { + decl := &ast.GenDecl{Tok: token.TYPE} + p.emitStmt(&ast.DeclStmt{Decl: decl}) + return &TypeDefs{decl: decl, scope: p.current.scope, pkg: p.pkg} } func getPos(pos []token.Pos) token.Pos { @@ -134,31 +207,23 @@ func getPos(pos []token.Pos) token.Pos { return pos[0] } -func (p *Package) appendGenDecl(scope *types.Scope, decl *ast.GenDecl) { - if scope == p.Types.Scope() { - p.file.decls = append(p.file.decls, decl) - } else { - p.cb.emitStmt(&ast.DeclStmt{Decl: decl}) - } -} - -func (p *Package) doNewType( - scope *types.Scope, pos token.Pos, name string, typ types.Type, alias token.Pos) *TypeDecl { +func (p *Package) doNewType(tdecl *TypeDefs, pos token.Pos, name string, typ types.Type, alias token.Pos) *TypeDecl { + scope := tdecl.scope typName := types.NewTypeName(pos, p.Types, name, typ) if old := scope.Insert(typName); old != nil { oldPos := p.cb.position(old.Pos()) p.cb.panicCodePosErrorf( pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldPos) } + decl := tdecl.decl spec := &ast.TypeSpec{Name: ident(name), Assign: alias} - decl := &ast.GenDecl{Tok: token.TYPE, Specs: []ast.Spec{spec}} + decl.Specs = append(decl.Specs, spec) if alias != 0 { // alias don't need to call InitType spec.Type = toType(p, typ) typ = typ.Underlying() // typ.Underlying() may delay load and can be nil, it's reasonable - p.appendGenDecl(scope, decl) } named := types.NewNamed(typName, typ, nil) - return &TypeDecl{typ: named, decl: decl, scope: scope} + return &TypeDecl{typ: named, spec: spec} } // ---------------------------------------------------------------------------- @@ -309,7 +374,7 @@ func (p *ValueDecl) endInit(cb *CodeBuilder, arity int) *ValueDecl { type VarDecl = ValueDecl func (p *Package) newValueDecl( - vdecl *ValueDefs, scope *types.Scope, pos token.Pos, tok token.Token, typ types.Type, names ...string) *ValueDecl { + spec ValueAt, scope *types.Scope, pos token.Pos, tok token.Token, typ types.Type, names ...string) *ValueDecl { n := len(names) if tok == token.DEFINE { // a, b := expr noNewVar := true @@ -347,7 +412,7 @@ func (p *Package) newValueDecl( } } } - spec := &ast.ValueSpec{Names: nameIdents} + spec.Names = nameIdents if typ != nil { if ut, ok := typ.(*unboundType); ok && ut.tBound == nil { ut.ptypes = append(ut.ptypes, &spec.Type) @@ -355,23 +420,11 @@ func (p *Package) newValueDecl( spec.Type = toType(p, typ) } } - at := -1 - if vdecl != nil { - decl := vdecl.decl - decl.Specs = append(decl.Specs, spec) - } else { - decl := &ast.GenDecl{Tok: tok, Specs: []ast.Spec{spec}} - if scope == p.Types.Scope() { - p.file.decls = append(p.file.decls, decl) - } else { - at = p.cb.startStmtAt(&ast.DeclStmt{Decl: decl}) - } - } return &ValueDecl{ - typ: typ, names: names, tok: tok, pos: pos, scope: scope, vals: &spec.Values, at: at} + typ: typ, names: names, tok: tok, pos: pos, scope: scope, vals: &spec.Values, at: spec.at} } -func (p *Package) newValueDefs(scope *types.Scope, tok token.Token) *ValueDefs { +func (p *Package) newValueDefs(scope *types.Scope, tok token.Token) *valueDefs { at := -1 decl := &ast.GenDecl{Tok: tok} if scope == p.Types.Scope() { @@ -379,7 +432,19 @@ func (p *Package) newValueDefs(scope *types.Scope, tok token.Token) *ValueDefs { } else { at = p.cb.startStmtAt(&ast.DeclStmt{Decl: decl}) } - return &ValueDefs{pkg: p, scope: scope, decl: decl, at: at} + return &valueDefs{pkg: p, scope: scope, decl: decl, at: at} +} + +func (p *CodeBuilder) valueDefs(tok token.Token) *valueDefs { + at := -1 + decl := &ast.GenDecl{Tok: tok} + pkg, scope := p.pkg, p.current.scope + if scope == pkg.Types.Scope() { + pkg.file.decls = append(pkg.file.decls, decl) + } else { + at = p.startStmtAt(&ast.DeclStmt{Decl: decl}) + } + return &valueDefs{pkg: pkg, scope: scope, decl: decl, at: at} } // NewConstStart creates constants with names. @@ -389,14 +454,8 @@ func (p *Package) NewConstStart(scope *types.Scope, pos token.Pos, typ types.Typ if debugInstr { log.Println("NewConst", names) } - return p.newValueDecl(nil, scope, pos, token.CONST, typ, names...).InitStart(p) -} - -// NewConstDecl starts a constant declaration block. -// -// Deprecated: Use NewConstDefs instead. -func (p *Package) NewConstDecl(scope *types.Scope) *ConstDefs { - return p.NewConstDefs(scope) + at := p.newValueDefs(scope, token.CONST).NewPos() + return p.newValueDecl(at, scope, pos, token.CONST, typ, names...).InitStart(p) } // NewConstDefs starts a constant declaration block. @@ -404,43 +463,48 @@ func (p *Package) NewConstDefs(scope *types.Scope) *ConstDefs { if debugInstr { log.Println("NewConstDefs") } - return &ConstDefs{ValueDefs: *p.newValueDefs(scope, token.CONST)} + return &ConstDefs{valueDefs: *p.newValueDefs(scope, token.CONST)} } // NewVar starts a var declaration block and creates uninitialized variables with // specified `typ` (can be nil) and `names`. // -// This is a shortcut for creating variables. `NewVarDefs` is more powerful and +// Deprecated: This is a shortcut for creating variables. `NewVarDefs` is more powerful and // more recommended. func (p *Package) NewVar(pos token.Pos, typ types.Type, names ...string) *VarDecl { if debugInstr { log.Println("NewVar", names) } - return p.newValueDecl(nil, p.Types.Scope(), pos, token.VAR, typ, names...) + scope := p.Types.Scope() + at := p.newValueDefs(scope, token.VAR).NewPos() + return p.newValueDecl(at, scope, pos, token.VAR, typ, names...) } // NewVarEx starts a var declaration block and creates uninitialized variables with // specified `typ` (can be nil) and `names`. // -// This is a shortcut for creating variables. `NewVarDefs` is more powerful and +// Deprecated: This is a shortcut for creating variables. `NewVarDefs` is more powerful and // more recommended. func (p *Package) NewVarEx(scope *types.Scope, pos token.Pos, typ types.Type, names ...string) *VarDecl { if debugInstr { log.Println("NewVar", names) } - return p.newValueDecl(nil, scope, pos, token.VAR, typ, names...) + at := p.newValueDefs(scope, token.VAR).NewPos() + return p.newValueDecl(at, scope, pos, token.VAR, typ, names...) } // NewVarStart creates variables with specified `typ` (can be nil) and `names` and starts // to initialize them. You should call `CodeBuilder.EndInit` to end initialization. // -// This is a shortcut for creating variables. `NewVarDefs` is more powerful and more +// Deprecated: This is a shortcut for creating variables. `NewVarDefs` is more powerful and more // recommended. func (p *Package) NewVarStart(pos token.Pos, typ types.Type, names ...string) *CodeBuilder { if debugInstr { log.Println("NewVar", names) } - return p.newValueDecl(nil, p.Types.Scope(), pos, token.VAR, typ, names...).InitStart(p) + scope := p.Types.Scope() + at := p.newValueDefs(scope, token.VAR).NewPos() + return p.newValueDecl(at, scope, pos, token.VAR, typ, names...).InitStart(p) } // NewVarDefs starts a var declaration block. @@ -448,34 +512,60 @@ func (p *Package) NewVarDefs(scope *types.Scope) *VarDefs { if debugInstr { log.Println("NewVarDefs") } - return (*VarDefs)(p.newValueDefs(scope, token.VAR)) + return &VarDefs{*p.newValueDefs(scope, token.VAR)} } // ---------------------------------------------------------------------------- -type ValueDefs struct { +type ValueAt struct { + *ast.ValueSpec + at int +} + +type valueDefs struct { decl *ast.GenDecl scope *types.Scope pkg *Package at int } -type VarDefs ValueDefs +func (p *valueDefs) NewPos() ValueAt { + decl := p.decl + spec := &ast.ValueSpec{} + decl.Specs = append(decl.Specs, spec) + return ValueAt{spec, p.at} +} + +// VarDefs represents a var declaration block. +type VarDefs struct { + valueDefs +} + +// SetComments sets associated documentation. +func (p *VarDefs) SetComments(doc *ast.CommentGroup) *VarDefs { + p.decl.Doc = doc + return p +} // New creates uninitialized variables with specified `typ` (can be nil) and `names`. func (p *VarDefs) New(pos token.Pos, typ types.Type, names ...string) *VarDecl { + return p.NewAt(p.NewPos(), pos, typ, names...) +} + +// NewAt creates uninitialized variables with specified `typ` (can be nil) and `names`. +func (p *VarDefs) NewAt(at ValueAt, pos token.Pos, typ types.Type, names ...string) *VarDecl { if debugInstr { log.Println("NewVar", names) } - return p.pkg.newValueDecl((*ValueDefs)(p), p.scope, pos, token.VAR, typ, names...) + return p.pkg.newValueDecl(at, p.scope, pos, token.VAR, typ, names...) } // NewAndInit creates variables with specified `typ` (can be nil) and `names`, and initializes them by `fn`. -func (p *VarDefs) NewAndInit(fn func(cb *CodeBuilder) int, pos token.Pos, typ types.Type, names ...string) *VarDefs { +func (p *VarDefs) NewAndInit(fn F, pos token.Pos, typ types.Type, names ...string) *VarDefs { if debugInstr { log.Println("NewAndInit", names) } - decl := p.pkg.newValueDecl((*ValueDefs)(p), p.scope, pos, token.VAR, typ, names...) + decl := p.pkg.newValueDecl(p.NewPos(), p.scope, pos, token.VAR, typ, names...) if fn != nil { cb := decl.InitStart(p.pkg) n := fn(cb) @@ -509,13 +599,17 @@ func (p *VarDefs) Delete(name string) error { // ---------------------------------------------------------------------------- +// F represents an initialization callback for constants/variables. +type F = func(cb *CodeBuilder) int + +// ConstDefs represents a const declaration block. type ConstDefs struct { - ValueDefs - fn func(cb *CodeBuilder) int + valueDefs typ types.Type + F F } -func constInitFn(cb *CodeBuilder, iotav int, fn func(cb *CodeBuilder) int) int { +func constInitFn(cb *CodeBuilder, iotav int, fn F) int { oldv := cb.iotav cb.iotav = iotav defer func() { @@ -524,23 +618,45 @@ func constInitFn(cb *CodeBuilder, iotav int, fn func(cb *CodeBuilder) int) int { return fn(cb) } -func (p *ConstDefs) New( - fn func(cb *CodeBuilder) int, iotav int, pos token.Pos, typ types.Type, names ...string) *ConstDefs { +// SetComments sets associated documentation. +func (p *ConstDefs) SetComments(doc *ast.CommentGroup) *ConstDefs { + p.decl.Doc = doc + return p +} + +// New creates constants with specified `typ` (can be nil) and `names`. +// The values of the constants are given by the callback `fn`. +func (p *ConstDefs) New(fn F, iotav int, pos token.Pos, typ types.Type, names ...string) *ConstDefs { + return p.NewAt(p.NewPos(), fn, iotav, pos, typ, names...) +} + +// NewAt creates constants with specified `typ` (can be nil) and `names`. +// The values of the constants are given by the callback `fn`. +func (p *ConstDefs) NewAt(at ValueAt, fn F, iotav int, pos token.Pos, typ types.Type, names ...string) *ConstDefs { if debugInstr { log.Println("NewConst", names, iotav) } pkg := p.pkg - cb := pkg.newValueDecl(&p.ValueDefs, p.scope, pos, token.CONST, typ, names...).InitStart(pkg) + cb := pkg.newValueDecl(at, p.scope, pos, token.CONST, typ, names...).InitStart(pkg) n := constInitFn(cb, iotav, fn) cb.EndInit(n) - p.fn, p.typ = fn, typ + p.F, p.typ = fn, typ return p } +// Next creates constants with specified `names`. +// The values of the constants are given by the callback `fn` which is +// specified by the last call to `New`. func (p *ConstDefs) Next(iotav int, pos token.Pos, names ...string) *ConstDefs { + return p.NextAt(p.NewPos(), p.F, iotav, pos, names...) +} + +// NextAt creates constants with specified `names`. +// The values of the constants are given by the callback `fn`. +func (p *ConstDefs) NextAt(at ValueAt, fn F, iotav int, pos token.Pos, names ...string) *ConstDefs { pkg := p.pkg cb := pkg.CB() - n := constInitFn(cb, iotav, p.fn) + n := constInitFn(cb, iotav, fn) if len(names) != n { if len(names) < n { cb.panicCodePosError(pos, "extra expression in const declaration") @@ -566,16 +682,10 @@ func (p *ConstDefs) Next(iotav int, pos token.Pos, names ...string) *ConstDefs { } idents[i] = ident(name) } - spec := &ast.ValueSpec{Names: idents} - p.decl.Specs = append(p.decl.Specs, spec) + at.Names = idents return p } -// ConstDecl type -// -// Deprecated: Use ConstDefs instead. -type ConstDecl = ConstDefs - // ---------------------------------------------------------------------------- var (