// Copyright 2009 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.

package eval

import (
	"go/ast";
	"go/token";
	"log";
)


/*
 * Type compiler
 */

type typeCompiler struct {
	*compiler;
	block	*block;
	// Check to be performed after a type declaration is compiled.
	//
	// TODO(austin) This will probably have to change after we
	// eliminate forward declarations.
	lateCheck	func() bool;
}

func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
	_, _, def := a.block.Lookup(x.Value);
	if def == nil {
		a.diagAt(x, "%s: undefined", x.Value);
		return nil;
	}
	switch def := def.(type) {
	case *Constant:
		a.diagAt(x, "constant %v used as type", x.Value);
		return nil;
	case *Variable:
		a.diagAt(x, "variable %v used as type", x.Value);
		return nil;
	case *NamedType:
		if !allowRec && def.incomplete {
			a.diagAt(x, "illegal recursive type");
			return nil;
		}
		if !def.incomplete && def.Def == nil {
			// Placeholder type from an earlier error
			return nil;
		}
		return def;
	case Type:
		return def;
	}
	log.Crashf("name %s has unknown type %T", x.Value, def);
	return nil;
}

func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
	// Compile element type
	elem := a.compileType(x.Elt, allowRec);

	// Compile length expression
	if x.Len == nil {
		if elem == nil {
			return nil;
		}
		return NewSliceType(elem);
	}

	if _, ok := x.Len.(*ast.Ellipsis); ok {
		a.diagAt(x.Len, "... array initailizers not implemented");
		return nil;
	}
	l, ok := a.compileArrayLen(a.block, x.Len);
	if !ok {
		return nil;
	}
	if l < 0 {
		a.diagAt(x.Len, "array length must be non-negative");
		return nil;
	}
	if elem == nil {
		return nil;
	}

	return NewArrayType(l, elem);
}

func countFields(fs []*ast.Field) int {
	n := 0;
	for _, f := range fs {
		if f.Names == nil {
			n++;
		} else {
			n += len(f.Names);
		}
	}
	return n;
}

func (a *typeCompiler) compileFields(fs []*ast.Field, allowRec bool) ([]Type, []*ast.Ident, []token.Position, bool) {
	n := countFields(fs);
	ts := make([]Type, n);
	ns := make([]*ast.Ident, n);
	ps := make([]token.Position, n);

	bad := false;
	i := 0;
	for _, f := range fs {
		t := a.compileType(f.Type, allowRec);
		if t == nil {
			bad = true;
		}
		if f.Names == nil {
			ns[i] = nil;
			ts[i] = t;
			ps[i] = f.Type.Pos();
			i++;
			continue;
		}
		for _, n := range f.Names {
			ns[i] = n;
			ts[i] = t;
			ps[i] = n.Pos();
			i++;
		}
	}

	return ts, ns, ps, bad;
}

func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type {
	ts, names, poss, bad := a.compileFields(x.Fields, allowRec);

	// XXX(Spec) The spec claims that field identifiers must be
	// unique, but 6g only checks this when they are accessed.  I
	// think the spec is better in this regard: if I write two
	// fields with the same name in the same struct type, clearly
	// that's a mistake.  This definition does *not* descend into
	// anonymous fields, so it doesn't matter if those change.
	// There's separate language in the spec about checking
	// uniqueness of field names inherited from anonymous fields
	// at use time.
	fields := make([]StructField, len(ts));
	nameSet := make(map[string]token.Position, len(ts));
	for i := range fields {
		// Compute field name and check anonymous fields
		var name string;
		if names[i] != nil {
			name = names[i].Value;
		} else {
			if ts[i] == nil {
				continue;
			}

			var nt *NamedType;
			// [For anonymous fields,] the unqualified
			// type name acts as the field identifier.
			switch t := ts[i].(type) {
			case *NamedType:
				name = t.Name;
				nt = t;
			case *PtrType:
				switch t := t.Elem.(type) {
				case *NamedType:
					name = t.Name;
					nt = t;
				}
			}
			// [An anonymous field] must be specified as a
			// type name T or as a pointer to a type name
			// *T, and T itself, may not be a pointer or
			// interface type.
			if nt == nil {
				a.diagAt(&poss[i], "embedded type must T or *T, where T is a named type");
				bad = true;
				continue;
			}
			// The check for embedded pointer types must
			// be deferred because of things like
			//  type T *struct { T }
			lateCheck := a.lateCheck;
			a.lateCheck = func() bool {
				if _, ok := nt.lit().(*PtrType); ok {
					a.diagAt(&poss[i], "embedded type %v is a pointer type", nt);
					return false;
				}
				return lateCheck();
			};
		}

		// Check name uniqueness
		if prev, ok := nameSet[name]; ok {
			a.diagAt(&poss[i], "field %s redeclared\n\tprevious declaration at %s", name, &prev);
			bad = true;
			continue;
		}
		nameSet[name] = poss[i];

		// Create field
		fields[i].Name = name;
		fields[i].Type = ts[i];
		fields[i].Anonymous = (names[i] == nil);
	}

	if bad {
		return nil;
	}

	return NewStructType(fields);
}

func (a *typeCompiler) compilePtrType(x *ast.StarExpr) Type {
	elem := a.compileType(x.X, true);
	if elem == nil {
		return nil;
	}
	return NewPtrType(elem);
}

func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl {
	// TODO(austin) Variadic function types

	// The types of parameters and results must be complete.
	//
	// TODO(austin) It's not clear they actually have to be complete.
	in, inNames, _, inBad := a.compileFields(x.Params, allowRec);
	out, outNames, _, outBad := a.compileFields(x.Results, allowRec);

	if inBad || outBad {
		return nil;
	}
	return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames};
}

func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) *InterfaceType {
	ts, names, poss, bad := a.compileFields(x.Methods, allowRec);

	methods := make([]IMethod, len(ts));
	nameSet := make(map[string]token.Position, len(ts));
	embeds := make([]*InterfaceType, len(ts));

	var nm, ne int;
	for i := range ts {
		if ts[i] == nil {
			continue;
		}

		if names[i] != nil {
			name := names[i].Value;
			methods[nm].Name = name;
			methods[nm].Type = ts[i].(*FuncType);
			nm++;
			if prev, ok := nameSet[name]; ok {
				a.diagAt(&poss[i], "method %s redeclared\n\tprevious declaration at %s", name, &prev);
				bad = true;
				continue;
			}
			nameSet[name] = poss[i];
		} else {
			// Embedded interface
			it, ok := ts[i].lit().(*InterfaceType);
			if !ok {
				a.diagAt(&poss[i], "embedded type must be an interface");
				bad = true;
				continue;
			}
			embeds[ne] = it;
			ne++;
			for _, m := range it.methods {
				if prev, ok := nameSet[m.Name]; ok {
					a.diagAt(&poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, &prev);
					bad = true;
					continue;
				}
				nameSet[m.Name] = poss[i];
			}
		}
	}

	if bad {
		return nil;
	}

	methods = methods[0:nm];
	embeds = embeds[0:ne];

	return NewInterfaceType(methods, embeds);
}

func (a *typeCompiler) compileMapType(x *ast.MapType) Type {
	key := a.compileType(x.Key, true);
	val := a.compileType(x.Value, true);
	if key == nil || val == nil {
		return nil;
	}
	// XXX(Spec) The Map types section explicitly lists all types
	// that can be map keys except for function types.
	switch key.lit().(type) {
	case *StructType:
		a.diagAt(x, "map key cannot be a struct type");
		return nil;
	case *ArrayType:
		a.diagAt(x, "map key cannot be an array type");
		return nil;
	case *SliceType:
		a.diagAt(x, "map key cannot be a slice type");
		return nil;
	}
	return NewMapType(key, val);
}

func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
	switch x := x.(type) {
	case *ast.BadExpr:
		// Error already reported by parser
		a.silentErrors++;
		return nil;

	case *ast.Ident:
		return a.compileIdent(x, allowRec);

	case *ast.ArrayType:
		return a.compileArrayType(x, allowRec);

	case *ast.StructType:
		return a.compileStructType(x, allowRec);

	case *ast.StarExpr:
		return a.compilePtrType(x);

	case *ast.FuncType:
		fd := a.compileFuncType(x, allowRec);
		if fd == nil {
			return nil;
		}
		return fd.Type;

	case *ast.InterfaceType:
		return a.compileInterfaceType(x, allowRec);

	case *ast.MapType:
		return a.compileMapType(x);

	case *ast.ChanType:
		goto notimpl;

	case *ast.ParenExpr:
		return a.compileType(x.X, allowRec);

	case *ast.Ellipsis:
		a.diagAt(x, "illegal use of ellipsis");
		return nil;
	}
	a.diagAt(x, "expression used as type");
	return nil;

notimpl:
	a.diagAt(x, "compileType: %T not implemented", x);
	return nil;
}

/*
 * Type compiler interface
 */

func noLateCheck() bool {
	return true;
}

func (a *compiler) compileType(b *block, typ ast.Expr) Type {
	tc := &typeCompiler{a, b, noLateCheck};
	t := tc.compileType(typ, false);
	if !tc.lateCheck() {
		t = nil;
	}
	return t;
}

func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
	ok := true;
	for _, spec := range decl.Specs {
		spec := spec.(*ast.TypeSpec);
		// Create incomplete type for this type
		nt := b.DefineType(spec.Name.Value, spec.Name.Pos(), nil);
		if nt != nil {
			nt.(*NamedType).incomplete = true;
		}
		// Compile type
		tc := &typeCompiler{a, b, noLateCheck};
		t := tc.compileType(spec.Type, false);
		if t == nil {
			// Create a placeholder type
			ok = false;
		}
		// Fill incomplete type
		if nt != nil {
			nt.(*NamedType).Complete(t);
		}
		// Perform late type checking with complete type
		if !tc.lateCheck() {
			ok = false;
			if nt != nil {
				// Make the type a placeholder
				nt.(*NamedType).Def = nil;
			}
		}
	}
	return ok;
}

func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
	tc := &typeCompiler{a, b, noLateCheck};
	res := tc.compileFuncType(typ, false);
	if res != nil {
		if !tc.lateCheck() {
			res = nil;
		}
	}
	return res;
}
