// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements NewPackage.

package ast

import (
	
	
	
	
)

type pkgBuilder struct {
	fset   *token.FileSet
	errors scanner.ErrorList
}

func ( *pkgBuilder) ( token.Pos,  string) {
	.errors.Add(.fset.Position(), )
}

func ( *pkgBuilder) ( token.Pos,  string,  ...interface{}) {
	.error(, fmt.Sprintf(, ...))
}

func ( *pkgBuilder) (,  *Scope,  *Object) {
	 := .Insert()
	if  == nil &&  != nil {
		// see if there is a conflicting declaration in altScope
		 = .Lookup(.Name)
	}
	if  != nil {
		 := ""
		if  := .Pos(); .IsValid() {
			 = fmt.Sprintf("\n\tprevious declaration at %s", .fset.Position())
		}
		.error(.Pos(), fmt.Sprintf("%s redeclared in this block%s", .Name, ))
	}
}

func resolve( *Scope,  *Ident) bool {
	for ;  != nil;  = .Outer {
		if  := .Lookup(.Name);  != nil {
			.Obj = 
			return true
		}
	}
	return false
}

// An Importer resolves import paths to package Objects.
// The imports map records the packages already imported,
// indexed by package id (canonical import path).
// An Importer must determine the canonical import path and
// check the map to see if it is already present in the imports map.
// If so, the Importer can return the map entry. Otherwise, the
// Importer should load the package data for the given path into
// a new *Object (pkg), record pkg in the imports map, and then
// return pkg.
type Importer func(imports map[string]*Object, path string) (pkg *Object, err error)

// NewPackage creates a new Package node from a set of File nodes. It resolves
// unresolved identifiers across files and updates each file's Unresolved list
// accordingly. If a non-nil importer and universe scope are provided, they are
// used to resolve identifiers not declared in any of the package files. Any
// remaining unresolved identifiers are reported as undeclared. If the files
// belong to different packages, one package name is selected and files with
// different package names are reported and then ignored.
// The result is a package node and a scanner.ErrorList if there were errors.
//
func ( *token.FileSet,  map[string]*File,  Importer,  *Scope) (*Package, error) {
	var  pkgBuilder
	.fset = 

	// complete package scope
	 := ""
	 := NewScope()
	for ,  := range  {
		// package names must match
		switch  := .Name.Name; {
		case  == "":
			 = 
		case  != :
			.errorf(.Package, "package %s; expected %s", , )
			continue // ignore this file
		}

		// collect top-level file objects in package scope
		for ,  := range .Scope.Objects {
			.declare(, nil, )
		}
	}

	// package global mapping of imported package ids to package objects
	 := make(map[string]*Object)

	// complete file scopes with imports and resolve identifiers
	for ,  := range  {
		// ignore file if it belongs to a different package
		// (error has already been reported)
		if .Name.Name !=  {
			continue
		}

		// build file scope by processing all imports
		 := false
		 := NewScope()
		for ,  := range .Imports {
			if  == nil {
				 = true
				continue
			}
			,  := strconv.Unquote(.Path.Value)
			,  := (, )
			if  != nil {
				.errorf(.Path.Pos(), "could not import %s (%s)", , )
				 = true
				continue
			}
			// TODO(gri) If a local package name != "." is provided,
			// global identifier resolution could proceed even if the
			// import failed. Consider adjusting the logic here a bit.

			// local name overrides imported package name
			 := .Name
			if .Name != nil {
				 = .Name.Name
			}

			// add import to file scope
			if  == "." {
				// merge imported scope with file scope
				for ,  := range .Data.(*Scope).Objects {
					.declare(, , )
				}
			} else if  != "_" {
				// declare imported package object in file scope
				// (do not re-use pkg in the file scope but create
				// a new object instead; the Decl field is different
				// for different files)
				 := NewObj(Pkg, )
				.Decl = 
				.Data = .Data
				.declare(, , )
			}
		}

		// resolve identifiers
		if  {
			// don't use the universe scope without correct imports
			// (objects in the universe may be shadowed by imports;
			// with missing imports, identifiers might get resolved
			// incorrectly to universe objects)
			.Outer = nil
		}
		 := 0
		for ,  := range .Unresolved {
			if !resolve(, ) {
				.errorf(.Pos(), "undeclared name: %s", .Name)
				.Unresolved[] = 
				++
			}

		}
		.Unresolved = .Unresolved[0:]
		.Outer =  // reset universe scope
	}

	.errors.Sort()
	return &Package{, , , }, .errors.Err()
}