github.com/goplus/gox@v1.14.13-0.20240308130321-6ff7f61cfae8/type_var_and_const.go (about)

     1  /*
     2   Copyright 2021 The GoPlus Authors (goplus.org)
     3   Licensed under the Apache License, Version 2.0 (the "License");
     4   you may not use this file except in compliance with the License.
     5   You may obtain a copy of the License at
     6       http://www.apache.org/licenses/LICENSE-2.0
     7   Unless required by applicable law or agreed to in writing, software
     8   distributed under the License is distributed on an "AS IS" BASIS,
     9   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10   See the License for the specific language governing permissions and
    11   limitations under the License.
    12  */
    13  
    14  package gox
    15  
    16  import (
    17  	"go/ast"
    18  	"go/token"
    19  	"go/types"
    20  	"log"
    21  	"syscall"
    22  
    23  	"github.com/goplus/gox/internal"
    24  )
    25  
    26  // ----------------------------------------------------------------------------
    27  
    28  // ConstStart starts a constant expression.
    29  func (p *Package) ConstStart() *CodeBuilder {
    30  	return &p.cb
    31  }
    32  
    33  func (p *CodeBuilder) EndConst() *Element {
    34  	return p.stk.Pop()
    35  }
    36  
    37  // ----------------------------------------------------------------------------
    38  
    39  // MethodToFunc:
    40  //
    41  //	(T).method
    42  //	(*T).method
    43  func (pkg *Package) MethodToFunc(typ types.Type, name string, src ...ast.Node) (ret *Element, err error) {
    44  	_, err = pkg.cb.Typ(typ, src...).Member(name, MemberFlagVal, src...)
    45  	ret = pkg.cb.stk.Pop()
    46  	return
    47  }
    48  
    49  // ----------------------------------------------------------------------------
    50  
    51  type TyState int
    52  
    53  const (
    54  	TyStateUninited TyState = iota
    55  	TyStateInited
    56  	TyStateDeleted
    57  )
    58  
    59  // TypeDecl type
    60  type TypeDecl struct {
    61  	typ  *types.Named
    62  	spec *ast.TypeSpec
    63  }
    64  
    65  // SetComments sets associated documentation.
    66  func (p *TypeDecl) SetComments(pkg *Package, doc *ast.CommentGroup) *TypeDecl {
    67  	p.spec.Doc = doc
    68  	pkg.setDoc(p.typ.Obj(), doc)
    69  	return p
    70  }
    71  
    72  // Type returns the type.
    73  func (p *TypeDecl) Type() *types.Named {
    74  	return p.typ
    75  }
    76  
    77  // State checkes state of this type.
    78  // If Delete is called, it returns TyStateDeleted.
    79  // If InitType is called (but not deleted), it returns TyStateInited.
    80  // Otherwise it returns TyStateUninited.
    81  func (p *TypeDecl) State() TyState {
    82  	spec := p.spec
    83  	if spec.Name != nil {
    84  		if spec.Type != nil {
    85  			return TyStateInited
    86  		}
    87  		return TyStateUninited
    88  	}
    89  	return TyStateDeleted
    90  }
    91  
    92  // Delete deletes this type.
    93  // NOTE: It panics if you call InitType after Delete.
    94  func (p *TypeDecl) Delete() {
    95  	p.spec.Name = nil
    96  }
    97  
    98  // Inited checkes if InitType is called or not.
    99  // Will panic if this type is deleted (please use State to check).
   100  func (p *TypeDecl) Inited() bool {
   101  	return p.spec.Type != nil
   102  }
   103  
   104  // InitType initializes a uncompleted type.
   105  func (p *TypeDecl) InitType(pkg *Package, typ types.Type, tparams ...*TypeParam) *types.Named {
   106  	if debugInstr {
   107  		log.Println("InitType", p.typ.Obj().Name(), typ)
   108  	}
   109  	spec := p.spec
   110  	if spec.Type != nil {
   111  		log.Panicln("TODO: type already defined -", typ)
   112  	}
   113  	if named, ok := typ.(*types.Named); ok {
   114  		p.typ.SetUnderlying(pkg.cb.getUnderlying(named))
   115  	} else {
   116  		p.typ.SetUnderlying(typ)
   117  	}
   118  	if tparams != nil {
   119  		setTypeParams(pkg, p.typ, spec, tparams)
   120  	}
   121  	spec.Type = toType(pkg, typ)
   122  	return p.typ
   123  }
   124  
   125  // ----------------------------------------------------------------------------
   126  
   127  // TypeDefs represents a type declaration block.
   128  type TypeDefs struct {
   129  	decl  *ast.GenDecl
   130  	scope *types.Scope
   131  	pkg   *Package
   132  }
   133  
   134  // Pkg returns the package instance.
   135  func (p *TypeDefs) Pkg() *Package {
   136  	return p.pkg
   137  }
   138  
   139  // SetComments sets associated documentation.
   140  func (p *TypeDefs) SetComments(doc *ast.CommentGroup) *TypeDefs {
   141  	p.decl.Doc = doc
   142  	return p
   143  }
   144  
   145  // NewType creates a new type (which need to call InitType later).
   146  func (p *TypeDefs) NewType(name string, src ...ast.Node) *TypeDecl {
   147  	if debugInstr {
   148  		log.Println("NewType", name)
   149  	}
   150  	return p.pkg.doNewType(p, getPos(src), name, nil, 0)
   151  }
   152  
   153  // AliasType gives a specified type with a new name.
   154  func (p *TypeDefs) AliasType(name string, typ types.Type, src ...ast.Node) *TypeDecl {
   155  	if debugInstr {
   156  		log.Println("AliasType", name, typ)
   157  	}
   158  	return p.pkg.doNewType(p, getPos(src), name, typ, 1)
   159  }
   160  
   161  // Complete checks type declarations & marks completed.
   162  func (p *TypeDefs) Complete() {
   163  	decl := p.decl
   164  	specs := decl.Specs
   165  	if len(specs) == 1 && decl.Doc == nil {
   166  		if spec := specs[0].(*ast.TypeSpec); spec.Doc != nil {
   167  			decl.Doc, spec.Doc = spec.Doc, nil
   168  		}
   169  	}
   170  	for i, spec := range specs {
   171  		v := spec.(*ast.TypeSpec)
   172  		if v.Name == nil || v.Type == nil {
   173  			for j := i + 1; j < len(specs); j++ {
   174  				v = specs[j].(*ast.TypeSpec)
   175  				if v.Name != nil && v.Type != nil {
   176  					specs[i] = v
   177  					i++
   178  				}
   179  			}
   180  			decl.Specs = specs[:i]
   181  			return
   182  		}
   183  	}
   184  }
   185  
   186  // ----------------------------------------------------------------------------
   187  
   188  // AliasType gives a specified type with a new name.
   189  //
   190  // Deprecated: use NewTypeDefs instead.
   191  func (p *Package) AliasType(name string, typ types.Type, src ...ast.Node) *types.Named {
   192  	decl := p.NewTypeDefs().AliasType(name, typ, src...)
   193  	return decl.typ
   194  }
   195  
   196  // NewType creates a new type (which need to call InitType later).
   197  //
   198  // Deprecated: use NewTypeDefs instead.
   199  func (p *Package) NewType(name string, src ...ast.Node) *TypeDecl {
   200  	return p.NewTypeDefs().NewType(name, src...)
   201  }
   202  
   203  // NewTypeDefs starts a type declaration block.
   204  func (p *Package) NewTypeDefs() *TypeDefs {
   205  	decl := &ast.GenDecl{Tok: token.TYPE}
   206  	p.file.decls = append(p.file.decls, decl)
   207  	return &TypeDefs{decl: decl, scope: p.Types.Scope(), pkg: p}
   208  }
   209  
   210  // NewTypeDefs starts a type declaration block.
   211  func (p *CodeBuilder) NewTypeDefs() *TypeDefs {
   212  	ret, defineHere := p.NewTypeDecls()
   213  	defineHere()
   214  	return ret
   215  }
   216  
   217  // NewTypeDecls starts a type declaration block but delay to define it.
   218  func (p *CodeBuilder) NewTypeDecls() (ret *TypeDefs, defineHere func()) {
   219  	pkg, scope := p.pkg, p.current.scope
   220  	decl := &ast.GenDecl{Tok: token.TYPE}
   221  	return &TypeDefs{decl: decl, scope: scope, pkg: pkg}, func() {
   222  		if scope == pkg.Types.Scope() {
   223  			pkg.file.decls = append(pkg.file.decls, decl)
   224  		} else {
   225  			p.emitStmt(&ast.DeclStmt{Decl: decl})
   226  		}
   227  	}
   228  }
   229  
   230  func (p *Package) doNewType(tdecl *TypeDefs, pos token.Pos, name string, typ types.Type, alias token.Pos) *TypeDecl {
   231  	scope := tdecl.scope
   232  	typName := types.NewTypeName(pos, p.Types, name, typ)
   233  	if old := scope.Insert(typName); old != nil {
   234  		oldPos := p.cb.fset.Position(old.Pos())
   235  		p.cb.panicCodeErrorf(
   236  			pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldPos)
   237  	}
   238  	decl := tdecl.decl
   239  	spec := &ast.TypeSpec{Name: ident(name), Assign: alias}
   240  	decl.Specs = append(decl.Specs, spec)
   241  	if alias != 0 { // alias don't need to call InitType
   242  		spec.Type = toType(p, typ)
   243  		typ = typ.Underlying() // typ.Underlying() may delay load and can be nil, it's reasonable
   244  	}
   245  	named := types.NewNamed(typName, typ, nil)
   246  	p.useName(name)
   247  	return &TypeDecl{typ: named, spec: spec}
   248  }
   249  
   250  // ----------------------------------------------------------------------------
   251  
   252  // ValueDecl type
   253  type ValueDecl struct {
   254  	names []string
   255  	typ   types.Type
   256  	old   codeBlock
   257  	oldv  *ValueDecl
   258  	scope *types.Scope
   259  	vals  *[]ast.Expr
   260  	tok   token.Token
   261  	pos   token.Pos
   262  	at    int // commitStmt(at)
   263  }
   264  
   265  // Inited checkes if `InitStart` is called or not.
   266  func (p *ValueDecl) Inited() bool {
   267  	return p.oldv != nil
   268  }
   269  
   270  // InitStart initializes a uninitialized variable or constant.
   271  func (p *ValueDecl) InitStart(pkg *Package) *CodeBuilder {
   272  	p.oldv, pkg.cb.valDecl = pkg.cb.valDecl, p
   273  	p.old = pkg.cb.startInitExpr(p)
   274  	return &pkg.cb
   275  }
   276  
   277  func (p *ValueDecl) Ref(name string) Ref {
   278  	return p.scope.Lookup(name)
   279  }
   280  
   281  // End is provided for internal usage.
   282  // Don't call it at any time. Please use (*CodeBuilder).EndInit instead.
   283  func (p *ValueDecl) End(cb *CodeBuilder, src ast.Node) {
   284  	fatal("don't call End(), please use EndInit() instead")
   285  }
   286  
   287  func (p *ValueDecl) resetInit(cb *CodeBuilder) *ValueDecl {
   288  	cb.endInitExpr(p.old)
   289  	if p.at >= 0 {
   290  		cb.commitStmt(p.at) // to support inline call, we must emitStmt at ResetInit stage
   291  	}
   292  	return p.oldv
   293  }
   294  
   295  func checkTuple(t **types.Tuple, typ types.Type) (ok bool) {
   296  	*t, ok = typ.(*types.Tuple)
   297  	return
   298  }
   299  
   300  func (p *ValueDecl) endInit(cb *CodeBuilder, arity int) *ValueDecl {
   301  	var t *types.Tuple
   302  	var values []ast.Expr
   303  	n := len(p.names)
   304  	rets := cb.stk.GetArgs(arity)
   305  	defer func() {
   306  		cb.stk.PopN(arity)
   307  		cb.endInitExpr(p.old)
   308  		if p.at >= 0 {
   309  			cb.commitStmt(p.at) // to support inline call, we must emitStmt at EndInit stage
   310  		}
   311  	}()
   312  	if arity == 1 && checkTuple(&t, rets[0].Type) {
   313  		if n != t.Len() {
   314  			caller := getCaller(rets[0])
   315  			cb.panicCodeErrorf(
   316  				p.pos, "assignment mismatch: %d variables but %s returns %d values", n, caller, t.Len())
   317  		}
   318  		*p.vals = []ast.Expr{rets[0].Val}
   319  		rets = make([]*internal.Elem, n)
   320  		for i := 0; i < n; i++ {
   321  			rets[i] = &internal.Elem{Type: t.At(i).Type()}
   322  		}
   323  	} else if n != arity {
   324  		if p.tok == token.CONST {
   325  			if n > arity {
   326  				cb.panicCodeError(p.pos, "missing value in const declaration")
   327  			}
   328  			cb.panicCodeError(p.pos, "extra expression in const declaration")
   329  		}
   330  		cb.panicCodeErrorf(p.pos, "assignment mismatch: %d variables but %d values", n, arity)
   331  	} else {
   332  		values = make([]ast.Expr, arity)
   333  		for i, ret := range rets {
   334  			values[i] = ret.Val
   335  		}
   336  		*p.vals = values
   337  	}
   338  	pkg, typ := cb.pkg, p.typ
   339  	if typ != nil {
   340  		for i, ret := range rets {
   341  			if err := matchType(pkg, ret, typ, "assignment"); err != nil {
   342  				panic(err)
   343  			}
   344  			if values != nil { // ret.Val may be changed
   345  				values[i] = ret.Val
   346  			}
   347  		}
   348  	}
   349  	for i, name := range p.names {
   350  		if name == "_" { // skip underscore
   351  			continue
   352  		}
   353  		pkg.useName(name)
   354  		if p.tok == token.CONST {
   355  			tv := rets[i]
   356  			if tv.CVal == nil {
   357  				src, _ := cb.loadExpr(tv.Src)
   358  				cb.panicCodeErrorf(
   359  					p.pos, "const initializer %s is not a constant", src)
   360  			}
   361  			tvType := typ
   362  			if tvType == nil {
   363  				tvType = tv.Type
   364  			}
   365  			if old := p.scope.Insert(types.NewConst(p.pos, pkg.Types, name, tvType, tv.CVal)); old != nil {
   366  				oldpos := cb.fset.Position(old.Pos())
   367  				cb.panicCodeErrorf(
   368  					p.pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldpos)
   369  			}
   370  		} else if typ == nil {
   371  			var retType = rets[i].Type
   372  			var parg *Element
   373  			if values != nil {
   374  				parg = &Element{Type: retType, Val: values[i]}
   375  			}
   376  			retType = DefaultConv(pkg, retType, parg)
   377  			if values != nil {
   378  				values[i] = parg.Val
   379  			}
   380  			if old := p.scope.Insert(types.NewVar(p.pos, pkg.Types, name, retType)); old != nil {
   381  				if p.tok != token.DEFINE {
   382  					oldpos := cb.fset.Position(old.Pos())
   383  					cb.panicCodeErrorf(
   384  						p.pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldpos)
   385  				}
   386  				if err := matchType(pkg, rets[i], old.Type(), "assignment"); err != nil {
   387  					panic(err)
   388  				}
   389  			}
   390  		}
   391  	}
   392  	return p.oldv
   393  }
   394  
   395  // VarDecl type
   396  type VarDecl = ValueDecl
   397  
   398  func (p *Package) newValueDecl(
   399  	spec ValueAt, scope *types.Scope, pos token.Pos, tok token.Token, typ types.Type, names ...string) *ValueDecl {
   400  	n := len(names)
   401  	if tok == token.DEFINE { // a, b := expr
   402  		noNewVar := true
   403  		nameIdents := make([]ast.Expr, n)
   404  		for i, name := range names {
   405  			nameIdents[i] = ident(name)
   406  			if noNewVar && scope.Lookup(name) == nil {
   407  				noNewVar = false
   408  			}
   409  		}
   410  		if noNewVar {
   411  			p.cb.handleCodeError(pos, "no new variables on left side of :=")
   412  		}
   413  		stmt := &ast.AssignStmt{Tok: token.DEFINE, Lhs: nameIdents}
   414  		at := p.cb.startStmtAt(stmt)
   415  		return &ValueDecl{names: names, tok: tok, pos: pos, scope: scope, vals: &stmt.Rhs, at: at}
   416  	} else if tok == token.CONST && len(names) == 1 && isGopoConst(names[0]) { // Gopo_XXX
   417  		p.isGopPkg = true
   418  	}
   419  	// var a, b = expr
   420  	// const a, b = expr
   421  	nameIdents := make([]*ast.Ident, n)
   422  	for i, name := range names {
   423  		nameIdents[i] = ident(name)
   424  		if name == "_" { // skip underscore
   425  			continue
   426  		}
   427  		if typ != nil && tok == token.VAR {
   428  			if old := scope.Insert(types.NewVar(pos, p.Types, name, typ)); old != nil {
   429  				allowRedecl := p.allowRedecl && scope == p.Types.Scope()
   430  				if !(allowRedecl && types.Identical(old.Type(), typ)) { // for c2go
   431  					oldpos := p.cb.fset.Position(old.Pos())
   432  					p.cb.panicCodeErrorf(
   433  						pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldpos)
   434  				}
   435  			}
   436  		}
   437  	}
   438  	spec.Names = nameIdents
   439  	if typ != nil {
   440  		if ut, ok := typ.(*unboundType); ok && ut.tBound == nil {
   441  			ut.ptypes = append(ut.ptypes, &spec.Type)
   442  		} else {
   443  			spec.Type = toType(p, typ)
   444  		}
   445  	}
   446  	return &ValueDecl{
   447  		typ: typ, names: names, tok: tok, pos: pos, scope: scope, vals: &spec.Values, at: spec.at}
   448  }
   449  
   450  func (p *Package) newValueDefs(scope *types.Scope, tok token.Token) *valueDefs {
   451  	at := -1
   452  	decl := &ast.GenDecl{Tok: tok}
   453  	if scope == p.Types.Scope() {
   454  		p.file.decls = append(p.file.decls, decl)
   455  	} else {
   456  		at = p.cb.startStmtAt(&ast.DeclStmt{Decl: decl})
   457  	}
   458  	return &valueDefs{pkg: p, scope: scope, decl: decl, at: at}
   459  }
   460  
   461  func (p *CodeBuilder) valueDefs(tok token.Token) *valueDefs {
   462  	at := -1
   463  	decl := &ast.GenDecl{Tok: tok}
   464  	pkg, scope := p.pkg, p.current.scope
   465  	if scope == pkg.Types.Scope() {
   466  		pkg.file.decls = append(pkg.file.decls, decl)
   467  	} else {
   468  		at = p.startStmtAt(&ast.DeclStmt{Decl: decl})
   469  	}
   470  	return &valueDefs{pkg: pkg, scope: scope, decl: decl, at: at}
   471  }
   472  
   473  // NewConstStart creates constants with names.
   474  //
   475  // Deprecated: Use NewConstDefs instead.
   476  func (p *Package) NewConstStart(scope *types.Scope, pos token.Pos, typ types.Type, names ...string) *CodeBuilder {
   477  	if debugInstr {
   478  		log.Println("NewConst", names)
   479  	}
   480  	at := p.newValueDefs(scope, token.CONST).NewPos()
   481  	return p.newValueDecl(at, scope, pos, token.CONST, typ, names...).InitStart(p)
   482  }
   483  
   484  // NewConstDefs starts a constant declaration block.
   485  func (p *Package) NewConstDefs(scope *types.Scope) *ConstDefs {
   486  	if debugInstr {
   487  		log.Println("NewConstDefs")
   488  	}
   489  	return &ConstDefs{valueDefs: *p.newValueDefs(scope, token.CONST)}
   490  }
   491  
   492  // NewVar starts a var declaration block and creates uninitialized variables with
   493  // specified `typ` (can be nil) and `names`.
   494  //
   495  // Deprecated: This is a shortcut for creating variables. `NewVarDefs` is more powerful and
   496  // more recommended.
   497  func (p *Package) NewVar(pos token.Pos, typ types.Type, names ...string) *VarDecl {
   498  	if debugInstr {
   499  		log.Println("NewVar", names)
   500  	}
   501  	scope := p.Types.Scope()
   502  	at := p.newValueDefs(scope, token.VAR).NewPos()
   503  	return p.newValueDecl(at, scope, pos, token.VAR, typ, names...)
   504  }
   505  
   506  // NewVarEx starts a var declaration block and creates uninitialized variables with
   507  // specified `typ` (can be nil) and `names`.
   508  //
   509  // Deprecated: This is a shortcut for creating variables. `NewVarDefs` is more powerful and
   510  // more recommended.
   511  func (p *Package) NewVarEx(scope *types.Scope, pos token.Pos, typ types.Type, names ...string) *VarDecl {
   512  	if debugInstr {
   513  		log.Println("NewVar", names)
   514  	}
   515  	at := p.newValueDefs(scope, token.VAR).NewPos()
   516  	return p.newValueDecl(at, scope, pos, token.VAR, typ, names...)
   517  }
   518  
   519  // NewVarStart creates variables with specified `typ` (can be nil) and `names` and starts
   520  // to initialize them. You should call `CodeBuilder.EndInit` to end initialization.
   521  //
   522  // Deprecated: This is a shortcut for creating variables. `NewVarDefs` is more powerful and more
   523  // recommended.
   524  func (p *Package) NewVarStart(pos token.Pos, typ types.Type, names ...string) *CodeBuilder {
   525  	if debugInstr {
   526  		log.Println("NewVar", names)
   527  	}
   528  	scope := p.Types.Scope()
   529  	at := p.newValueDefs(scope, token.VAR).NewPos()
   530  	return p.newValueDecl(at, scope, pos, token.VAR, typ, names...).InitStart(p)
   531  }
   532  
   533  // NewVarDefs starts a var declaration block.
   534  func (p *Package) NewVarDefs(scope *types.Scope) *VarDefs {
   535  	if debugInstr {
   536  		log.Println("NewVarDefs")
   537  	}
   538  	return &VarDefs{*p.newValueDefs(scope, token.VAR)}
   539  }
   540  
   541  // ----------------------------------------------------------------------------
   542  
   543  type ValueAt struct {
   544  	*ast.ValueSpec
   545  	at int
   546  }
   547  
   548  type valueDefs struct {
   549  	decl  *ast.GenDecl
   550  	scope *types.Scope
   551  	pkg   *Package
   552  	at    int
   553  }
   554  
   555  func (p *valueDefs) NewPos() ValueAt {
   556  	decl := p.decl
   557  	spec := &ast.ValueSpec{}
   558  	decl.Specs = append(decl.Specs, spec)
   559  	return ValueAt{spec, p.at}
   560  }
   561  
   562  // VarDefs represents a var declaration block.
   563  type VarDefs struct {
   564  	valueDefs
   565  }
   566  
   567  // SetComments sets associated documentation.
   568  func (p *VarDefs) SetComments(doc *ast.CommentGroup) *VarDefs {
   569  	p.decl.Doc = doc
   570  	return p
   571  }
   572  
   573  // New creates uninitialized variables with specified `typ` (can be nil) and `names`.
   574  func (p *VarDefs) New(pos token.Pos, typ types.Type, names ...string) *VarDecl {
   575  	return p.NewAt(p.NewPos(), pos, typ, names...)
   576  }
   577  
   578  // NewAt creates uninitialized variables with specified `typ` (can be nil) and `names`.
   579  func (p *VarDefs) NewAt(at ValueAt, pos token.Pos, typ types.Type, names ...string) *VarDecl {
   580  	if debugInstr {
   581  		log.Println("NewVar", names)
   582  	}
   583  	return p.pkg.newValueDecl(at, p.scope, pos, token.VAR, typ, names...)
   584  }
   585  
   586  // NewAndInit creates variables with specified `typ` (can be nil) and `names`, and initializes them by `fn`.
   587  func (p *VarDefs) NewAndInit(fn F, pos token.Pos, typ types.Type, names ...string) *VarDefs {
   588  	if debugInstr {
   589  		log.Println("NewAndInit", names)
   590  	}
   591  	decl := p.pkg.newValueDecl(p.NewPos(), p.scope, pos, token.VAR, typ, names...)
   592  	if fn != nil {
   593  		cb := decl.InitStart(p.pkg)
   594  		n := fn(cb)
   595  		cb.EndInit(n)
   596  	}
   597  	return p
   598  }
   599  
   600  // Delete deletes an uninitialized variable who was created by `New`.
   601  // If the variable is initialized, it fails to delete and returns `syscall.EACCES`.
   602  // If the variable is not found, it returns `syscall.ENOENT`.
   603  func (p *VarDefs) Delete(name string) error {
   604  	for i, spec := range p.decl.Specs {
   605  		vspec := spec.(*ast.ValueSpec)
   606  		for j, ident := range vspec.Names {
   607  			if ident.Name == name {
   608  				if vspec.Values != nil { // can't remove an initialized variable
   609  					return syscall.EACCES
   610  				}
   611  				if len(vspec.Names) == 1 {
   612  					p.decl.Specs = append(p.decl.Specs[:i], p.decl.Specs[i+1:]...)
   613  					return nil
   614  				}
   615  				vspec.Names = append(vspec.Names[:j], vspec.Names[j+1:]...)
   616  				return nil
   617  			}
   618  		}
   619  	}
   620  	return syscall.ENOENT
   621  }
   622  
   623  // ----------------------------------------------------------------------------
   624  
   625  // F represents an initialization callback for constants/variables.
   626  type F = func(cb *CodeBuilder) int
   627  
   628  // ConstDefs represents a const declaration block.
   629  type ConstDefs struct {
   630  	valueDefs
   631  	typ types.Type
   632  	F   F
   633  }
   634  
   635  func constInitFn(cb *CodeBuilder, iotav int, fn F) int {
   636  	oldv := cb.iotav
   637  	cb.iotav = iotav
   638  	defer func() {
   639  		cb.iotav = oldv
   640  	}()
   641  	return fn(cb)
   642  }
   643  
   644  // SetComments sets associated documentation.
   645  func (p *ConstDefs) SetComments(doc *ast.CommentGroup) *ConstDefs {
   646  	p.decl.Doc = doc
   647  	return p
   648  }
   649  
   650  // New creates constants with specified `typ` (can be nil) and `names`.
   651  // The values of the constants are given by the callback `fn`.
   652  func (p *ConstDefs) New(fn F, iotav int, pos token.Pos, typ types.Type, names ...string) *ConstDefs {
   653  	return p.NewAt(p.NewPos(), fn, iotav, pos, typ, names...)
   654  }
   655  
   656  // NewAt creates constants with specified `typ` (can be nil) and `names`.
   657  // The values of the constants are given by the callback `fn`.
   658  func (p *ConstDefs) NewAt(at ValueAt, fn F, iotav int, pos token.Pos, typ types.Type, names ...string) *ConstDefs {
   659  	if debugInstr {
   660  		log.Println("NewConst", names, iotav)
   661  	}
   662  	pkg := p.pkg
   663  	cb := pkg.newValueDecl(at, p.scope, pos, token.CONST, typ, names...).InitStart(pkg)
   664  	n := constInitFn(cb, iotav, fn)
   665  	cb.EndInit(n)
   666  	p.F, p.typ = fn, typ
   667  	return p
   668  }
   669  
   670  // Next creates constants with specified `names`.
   671  // The values of the constants are given by the callback `fn` which is
   672  // specified by the last call to `New`.
   673  func (p *ConstDefs) Next(iotav int, pos token.Pos, names ...string) *ConstDefs {
   674  	return p.NextAt(p.NewPos(), p.F, iotav, pos, names...)
   675  }
   676  
   677  // NextAt creates constants with specified `names`.
   678  // The values of the constants are given by the callback `fn`.
   679  func (p *ConstDefs) NextAt(at ValueAt, fn F, iotav int, pos token.Pos, names ...string) *ConstDefs {
   680  	pkg := p.pkg
   681  	cb := pkg.CB()
   682  	n := constInitFn(cb, iotav, fn)
   683  	if len(names) != n {
   684  		if len(names) < n {
   685  			cb.panicCodeError(pos, "extra expression in const declaration")
   686  		}
   687  		cb.panicCodeError(pos, "missing value in const declaration")
   688  	}
   689  
   690  	ret := cb.stk.GetArgs(n)
   691  	defer cb.stk.PopN(n)
   692  
   693  	idents := make([]*ast.Ident, n)
   694  	for i, name := range names {
   695  		typ := p.typ
   696  		if typ == nil {
   697  			typ = ret[i].Type
   698  		}
   699  		if name != "_" {
   700  			if old := p.scope.Insert(types.NewConst(pos, pkg.Types, name, typ, ret[i].CVal)); old != nil {
   701  				oldpos := cb.fset.Position(old.Pos())
   702  				cb.panicCodeErrorf(
   703  					pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldpos)
   704  			}
   705  		}
   706  		idents[i] = ident(name)
   707  	}
   708  	at.Names = idents
   709  	return p
   710  }
   711  
   712  // ----------------------------------------------------------------------------