// Export = "PackageClause { Decl } "$$" . // PackageClause = "package" identifier [ "safe" ] "\n" . // func (p *gcParser) parseExport() *ast.Object { p.expectKeyword("package") name := p.expect(scanner.Ident) if p.tok != '\n' { // A package is safe if it was compiled with the -u flag, // which disables the unsafe package. // TODO(gri) remember "safe" package p.expectKeyword("safe") } p.expect('\n') assert(p.imports[p.id] == nil) pkg := ast.NewObj(ast.Pkg, name) pkg.Data = ast.NewScope(nil) p.imports[p.id] = pkg for p.tok != '$' && p.tok != scanner.EOF { p.parseDecl() } if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' { // don't call next()/expect() since reading past the // export data may cause scanner errors (e.g. NUL chars) p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch) } if n := p.scanner.ErrorCount; n != 0 { p.errorf("expected no scanner errors, got %d", n) } return pkg }
func define(kind ast.ObjKind, name string) *ast.Object { obj := ast.NewObj(kind, name) if scope.Insert(obj) != nil { panic("types internal error: double declaration") } return obj }
// ExportedName = ImportPath "." dotIdentifier . // func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object { pkg := p.parsePkgId() p.expect('.') name := p.parseDotIdent() // a type may have been declared before - if it exists // already in the respective package scope, return that // type scope := pkg.Data.(*ast.Scope) 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: %s", 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 }
// ImportPath = string_lit . // func (p *gcParser) parsePkgId() *ast.Object { id, err := strconv.Unquote(p.expect(scanner.String)) if err != nil { p.error(err) } switch id { case "": // id == "" stands for the imported package id // (only known at time of package installation) id = p.id case "unsafe": // package unsafe is not in the imports map - handle explicitly return Unsafe } pkg := p.imports[id] if pkg == nil { scope = ast.NewScope(nil) pkg = ast.NewObj(ast.Pkg, "") pkg.Data = scope p.imports[id] = pkg } return pkg }
func init() { scope = ast.NewScope(nil) Universe = scope Bool = defType("bool") defType("byte") // TODO(gri) should be an alias for uint8 defType("complex64") Complex128 = defType("complex128") defType("float32") Float64 = defType("float64") defType("int8") defType("int16") defType("int32") defType("int64") String = defType("string") defType("uint8") defType("uint16") defType("uint32") defType("uint64") Int = defType("int") defType("uint") defType("uintptr") defConst("true") defConst("false") defConst("iota") defConst("nil") defFun("append") defFun("cap") defFun("close") defFun("complex") defFun("copy") defFun("imag") defFun("len") defFun("make") defFun("new") defFun("panic") defFun("print") defFun("println") defFun("real") defFun("recover") scope = ast.NewScope(nil) Unsafe = ast.NewObj(ast.Pkg, "unsafe") Unsafe.Data = scope defType("Pointer") defFun("Alignof") defFun("New") defFun("NewArray") defFun("Offsetof") defFun("Reflect") defFun("Sizeof") defFun("Typeof") defFun("Unreflect") }
// findField returns the object with the given name if visible in the type's scope. // If no such object is found, an error is reported and a bad object is returned instead. func (tc *typechecker) findField(typ *Type, name *ast.Ident) (obj *ast.Object) { // TODO(gri) This is simplistic at the moment and ignores anonymous fields. obj = typ.Scope.Lookup(name.Name) if obj == nil { tc.Errorf(name.Pos(), "%s not declared", name.Name) obj = ast.NewObj(ast.Bad, name.Name) } return }
// find returns the object with the given name if visible in the current scope hierarchy. // If no such object is found, an error is reported and a bad object is returned instead. func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) { for s := tc.topScope; s != nil && obj == nil; s = s.Outer { obj = s.Lookup(name.Name) } if obj == nil { tc.Errorf(name.Pos(), "%s not declared", name.Name) obj = ast.NewObj(ast.Bad, name.Name) } name.Obj = obj return }
// 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 }
// collectFields collects struct fields tok = token.STRUCT), interface methods // (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC). func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) { if list != nil { for _, field := range list.List { ftype := field.Type if t, ok := ftype.(*ast.Ellipsis); ok { ftype = t.Elt isVariadic = true } typ := c.makeType(ftype, cycleOk) tag := "" if field.Tag != nil { assert(field.Tag.Kind == token.STRING) tag, _ = strconv.Unquote(field.Tag.Value) } if len(field.Names) > 0 { // named fields for _, name := range field.Names { obj := name.Obj obj.Type = typ fields = append(fields, obj) if tok == token.STRUCT { tags = append(tags, tag) } } } else { // anonymous field switch tok { case token.STRUCT: tags = append(tags, tag) fallthrough case token.FUNC: obj := ast.NewObj(ast.Var, "") obj.Type = typ fields = append(fields, obj) case token.INTERFACE: utyp := Underlying(typ) if typ, ok := utyp.(*Interface); ok { // TODO(gri) This is not good enough. Check for double declarations! fields = append(fields, typ.Methods...) } else if _, ok := utyp.(*Bad); !ok { // if utyp is Bad, don't complain (the root cause was reported before) c.errorf(ftype.Pos(), "interface contains embedded non-interface type") } default: panic("unreachable") } } } } return }
// MethodSpec = identifier Signature . // func (p *gcParser) parseMethodSpec() *ast.Object { if p.tok == scanner.Ident { p.expect(scanner.Ident) } else { // TODO(gri) should this be parseExportedName here? p.parsePkgId() p.expect('.') p.parseDotIdent() } p.parseSignature() // TODO(gri) compute method object return ast.NewObj(ast.Fun, "_") }
func init() { Universe = ast.NewScope(nil) // basic types for n, name := range BasicTypes { typ := NewType(Basic) typ.N = n obj := ast.NewObj(ast.Typ, name) obj.Type = typ typ.Obj = obj def(obj) } // built-in functions // TODO(gri) implement this }
// Field = Name Type [ ":" string_lit ] . // func (p *gcParser) parseField() (fld *ast.Object, tag string) { name := p.parseName() ftyp := p.parseType() if name == "" { // anonymous field - ftyp must be T or *T and T must be a type name if _, ok := Deref(ftyp).(*Name); !ok { p.errorf("anonymous field expected") } } if p.tok == ':' { p.next() tag = p.expect(scanner.String) } fld = ast.NewObj(ast.Var, name) fld.Type = ftyp return }
// Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] . // func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) { name := p.parseName() if name == "" { name = "_" // cannot access unnamed identifiers } if p.tok == '.' { p.expectSpecial("...") isVariadic = true } ptyp := p.parseType() // ignore argument tag if p.tok == ':' { p.next() p.expect(scanner.String) } par = ast.NewObj(ast.Var, name) par.Type = ptyp return }
// Signature = Parameters [ Result ] . // Result = Type | Parameters . // func (p *gcParser) parseSignature() *Func { params, isVariadic := p.parseParameters() // optional result type var results []*ast.Object switch p.tok { case scanner.Ident, scanner.String, '[', '*', '<': // single, unnamed result result := ast.NewObj(ast.Var, "_") result.Type = p.parseType() results = []*ast.Object{result} case '(': // named or multiple result(s) var variadic bool results, variadic = p.parseParameters() if variadic { p.error("... not permitted on result type") } } return &Func{Params: params, Results: results, IsVariadic: isVariadic} }