// 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}
}