// Declare inserts a named object of the given kind in scope. func (p *gcParser) declare(scope *ast.Scope, kind ast.ObjKind, name string) *ast.Object { // a type may have been declared before - if it exists // already in the respective package scope, return that // type if kind == ast.Typ { if obj := scope.Lookup(name); obj != nil { assert(obj.Kind == ast.Typ) return obj } } // any other object must be a newly declared object - // create it and insert it into the package scope obj := ast.NewObj(kind, name) if scope.Insert(obj) != nil { p.errorf("already declared: %v %s", kind, obj.Name) } // a new type object is a named type and may be referred // to before the underlying type is known - set it up if kind == ast.Typ { obj.Type = &Name{Obj: obj} } return obj }
func insertToScope(scope *ast.Scope, obj *ast.Object) { if obj.Name == "_" { return } if obj.Kind == ast.Fun && obj.Name == "init" { return } scope.Insert(obj) }
func Lookup(scope *ast.Scope, name string) *ast.Object { for scope != nil { if obj := scope.Lookup(name); obj != nil { return obj } scope = scope.Outer } return nil }
// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields. // It returns the newly allocated object. If an object with the same name already exists in scope, an error // is reported and the object is not inserted. // (Objects with _ name are always inserted into a scope without errors, but they cannot be found.) func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object { obj := ast.NewObj(kind, name.Name) obj.Decl = decl obj.N = n name.Obj = obj if alt := scope.Insert(obj); alt != obj { tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt)) } return obj }
func (p *parser) declIdent(scope *ast.Scope, id *ast.Ident) { decl := scope.Declare(id.Obj) if p.checkDecl && decl != id.Obj { if decl.Kind == ast.Err { // declared object is a forward declaration - update it *decl = *id.Obj id.Obj = decl return } p.Error(id.Pos(), "'"+id.Name()+"' declared already at "+decl.Pos.String()) } }
// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields. // It returns the newly allocated object. If an object with the same name already exists in scope, an error // is reported and the object is not inserted. func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object { obj := ast.NewObj(kind, name.Name) obj.Decl = decl //obj.N = n name.Obj = obj if name.Name != "_" { if alt := scope.Insert(obj); alt != nil { tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String()) } } return obj }
// declare declares an object of the given kind and name (ident) in scope; // decl is the corresponding declaration in the AST. An error is reported // if the object was declared before. // // TODO(gri) This is very similar to the declare function in go/parser; it // is only used to associate methods with their respective receiver base types. // In a future version, it might be simpler and cleaner to do all the resolution // in the type-checking phase. It would simplify the parser, AST, and also // reduce some amount of code duplication. // func (check *checker) declare(scope *ast.Scope, kind ast.ObjKind, ident *ast.Ident, decl ast.Decl) { assert(ident.Obj == nil) // identifier already declared or resolved obj := ast.NewObj(kind, ident.Name) obj.Decl = decl ident.Obj = obj if ident.Name != "_" { if alt := scope.Insert(obj); alt != nil { prevDecl := "" if pos := alt.Pos(); pos.IsValid() { prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", check.fset.Position(pos)) } check.errorf(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl)) } } }
// Signature = Parameters [ Result ] . // Result = Type | Parameters . // func (p *gcParser) parseSignature(scope *ast.Scope, isVariadic *bool) { p.parseParameters(scope, isVariadic) // optional result type switch p.tok { case scanner.Ident, scanner.String, '[', '*', '<': // single, unnamed result result := ast.NewObj(ast.Var, "_") result.Type = p.parseType() scope.Insert(result) case '(': // named or multiple result(s) p.parseParameters(scope, nil) } }
func (p *parser) findIdentInScope(scope *ast.Scope) *ast.Ident { pos := p.pos name := "_" var obj *ast.Object if p.tok == token.IDENT { name = string(p.lit) obj = scope.Lookup(name) p.next() } else { p.expect(token.IDENT) // use expect() error handling } if obj == nil { // TODO(gri) At the moment we always arrive here because // we don't track the lookup scope (and sometimes // we can't). Just create a useable ident for now. obj = ast.NewObj(ast.Err, pos, name) } return &ast.Ident{pos, obj} }
// Parameter = ( identifier | "?" ) [ "..." ] Type . // func (p *gcParser) parseParameter(scope *ast.Scope, isVariadic *bool) { name := p.parseName() if name == "" { name = "_" // cannot access unnamed identifiers } if isVariadic != nil { if *isVariadic { p.error("... not on final argument") } if p.tok == '.' { p.expectSpecial("...") *isVariadic = true } } ptyp := p.parseType() par := ast.NewObj(ast.Var, name) par.Type = ptyp scope.Insert(par) }
func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) { for _, ident := range idents { assert(ident.Obj == nil, "identifier already declared or resolved") obj := ast.NewObj(kind, ident.Name) // remember the corresponding declaration for redeclaration // errors and global variable resolution/typechecking phase obj.Decl = decl obj.Data = data ident.Obj = obj if ident.Name != "_" { if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 { prevDecl := "" if pos := alt.Pos(); pos.IsValid() { prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.file.Position(pos)) } p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl)) } } } }
// Declare inserts a named object of the given kind in scope. func (p *gcParser) declare(scope *ast.Scope, kind ast.ObjKind, name string) *ast.Object { // the object may have been imported before - if it exists // already in the respective package scope, return that object if obj := scope.Lookup(name); obj != nil { assert(obj.Kind == kind) return obj } // otherwise create a new object and insert it into the package scope obj := ast.NewObj(kind, name) if scope.Insert(obj) != nil { p.errorf("already declared: %v %s", kind, obj.Name) } // if the new type object is a named type it may be referred // to before the underlying type is known - set it up if kind == ast.Typ { obj.Type = &NamedType{Obj: obj} } return obj }
// Field = Name Type [ ":" string_lit ] . // func (p *gcParser) parseField(scope *ast.Scope) { // TODO(gri) The code below is not correct for anonymous fields: // The name is the type name; it should not be empty. name := p.parseName() ftyp := p.parseType() if name == "" { // anonymous field - ftyp must be T or *T and T must be a type name ftyp = Deref(ftyp) if ftyp, ok := ftyp.(*Name); ok { name = ftyp.Obj.Name } else { p.errorf("anonymous field expected") } } if p.tok == ':' { p.next() tag := p.expect(scanner.String) _ = tag // TODO(gri) store tag somewhere } fld := ast.NewObj(ast.Var, name) fld.Type = ftyp scope.Insert(fld) }