// specValues returns the list of initialization expressions // for the given part (spec) of a constant declaration. // TODO(gri) Make this more efficient by caching results // (using a map in checker). func (check *checker) specValues(spec *ast.ValueSpec) []ast.Expr { if len(spec.Values) > 0 { return spec.Values } // find the corresponding values for _, file := range check.pkg.Files { for _, d := range file.Decls { if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.CONST { var values []ast.Expr for _, s := range d.Specs { if s, ok := s.(*ast.ValueSpec); ok { if len(s.Values) > 0 { values = s.Values } if s == spec { return values } } } } } } check.invalidAST(spec.Pos(), "no initialization values provided") return nil }
func (p *parser) parseValueSpec(n *parse.Node) *ast.ValueSpec { n = n.Child(0) spec := ast.ValueSpec{} if n.Is(identifierList) { spec.Names = p.parseIdentList(n) } else { spec.Names = p.parseIdentList(n.Child(0)) if n.Child(1).Is(type_) { spec.Type = p.parseType(n.Child(1)) } spec.Values = p.parseExprList(n.LastChild()) } return &spec }
// arityMatch checks that the lhs and rhs of a const or var decl // have the appropriate number of names and init exprs. For const // decls, init is the value spec providing the init exprs; for // var decls, init is nil (the init exprs are in s in this case). func (check *checker) arityMatch(s, init *ast.ValueSpec) { l := len(s.Names) r := len(s.Values) if init != nil { r = len(init.Values) } switch { case init == nil && r == 0: // var decl w/o init expr if s.Type == nil { check.errorf(s.Pos(), "missing type or init expr") } case l < r: if l < len(s.Values) { // init exprs from s n := s.Values[l] check.errorf(n.Pos(), "extra init expr %s", n) } else { // init exprs "inherited" check.errorf(s.Pos(), "extra init expr at %s", init.Pos()) } case l > r && (init != nil || r != 1): n := s.Names[r] check.errorf(n.Pos(), "missing init expr for %s", n) } }