func get_type_path(e ast.Expr) (r type_path) {
	if e == nil {
		return type_path{"", ""}
	}
	switch t := e.(type) {
	case *ast.Ident:
		r.name = t.Name
	case *ast.StarExpr:
		r = get_type_path(t.X)
	case *ast.SelectorExpr:
		if ident, ok := t.X.(*ast.Ident); ok {
			r.pkg = ident.Name
		}
		r.name = t.Sel.Name
	}
	return
}
converts type expressions like:
ast.Expr
*ast.Expr
$ast$go/ast.Expr
to a path that can be used to lookup a type related Decl
package gocode
import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"
	"io"
	"reflect"
	"strings"
	"sync"
)
type decl_class int16
const (
	decl_invalid = decl_class(-1 + iota)
	decl_const
	decl_func
	decl_package
	decl_type
	decl_var
	decl_methods_stub
)
func (this decl_class) String() string {
	switch this {
	case decl_invalid:
		return "PANIC"
	case decl_const:
		return "const"
	case decl_func:
		return "func"
	case decl_package:
		return "package"
	case decl_type:
		return "type"
	case decl_var:
		return "var"
	case decl_methods_stub:
		return "IF YOU SEE THIS, REPORT A BUG"  
	}
	panic("unreachable")
}
type decl_flags int16
const (
	decl_foreign = decl_flags(1 << iota)  
	decl_rangevar
	decl_visited
)
type decl struct {
	name  string
	typ   ast.Expr
	class decl_class
	flags decl_flags
	children map[string]*decl
	embedded []ast.Expr
	value ast.Expr
	value_index int
	scope *scope
}
func ast_decl_type(d ast.Decl) ast.Expr {
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.CONST, token.VAR:
			c := t.Specs[0].(*ast.ValueSpec)
			return c.Type
		case token.TYPE:
			t := t.Specs[0].(*ast.TypeSpec)
			return t.Type
		}
	case *ast.FuncDecl:
		return t.Type
	}
	panic("unreachable")
	return nil
}
func ast_decl_class(d ast.Decl) decl_class {
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.VAR:
			return decl_var
		case token.CONST:
			return decl_const
		case token.TYPE:
			return decl_type
		}
	case *ast.FuncDecl:
		return decl_func
	}
	panic("unreachable")
}
func ast_decl_convertable(d ast.Decl) bool {
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.VAR, token.CONST, token.TYPE:
			return true
		}
	case *ast.FuncDecl:
		return true
	}
	return false
}
func ast_field_list_to_decls(f *ast.FieldList, class decl_class, flags decl_flags, scope *scope, add_anonymous bool) map[string]*decl {
	count := 0
	for _, field := range f.List {
		count += len(field.Names)
	}
	decls := make(map[string]*decl, count)
	for _, field := range f.List {
		for _, name := range field.Names {
			if flags&decl_foreign != 0 && !ast.IsExported(name.Name) {
				continue
			}
			d := &decl{
				name:        name.Name,
				typ:         field.Type,
				class:       class,
				flags:       flags,
				scope:       scope,
				value_index: -1,
			}
			decls[d.name] = d
		}
		if class == decl_var && field.Names == nil && add_anonymous {
			tp := get_type_path(field.Type)
			if flags&decl_foreign != 0 && !ast.IsExported(tp.name) {
				continue
			}
			d := &decl{
				name:        tp.name,
				typ:         field.Type,
				class:       class,
				flags:       flags,
				scope:       scope,
				value_index: -1,
			}
			decls[d.name] = d
		}
	}
	return decls
}
func ast_field_list_to_embedded(f *ast.FieldList) []ast.Expr {
	count := 0
	for _, field := range f.List {
		if field.Names == nil || field.Names[0].Name == "?" {
			count++
		}
	}
	if count == 0 {
		return nil
	}
	embedded := make([]ast.Expr, count)
	i := 0
	for _, field := range f.List {
		if field.Names == nil || field.Names[0].Name == "?" {
			embedded[i] = field.Type
			i++
		}
	}
	return embedded
}
func ast_type_to_embedded(ty ast.Expr) []ast.Expr {
	switch t := ty.(type) {
	case *ast.StructType:
		return ast_field_list_to_embedded(t.Fields)
	case *ast.InterfaceType:
		return ast_field_list_to_embedded(t.Methods)
	}
	return nil
}
func ast_type_to_children(ty ast.Expr, flags decl_flags, scope *scope) map[string]*decl {
	switch t := ty.(type) {
	case *ast.StructType:
		return ast_field_list_to_decls(t.Fields, decl_var, flags, scope, true)
	case *ast.InterfaceType:
		return ast_field_list_to_decls(t.Methods, decl_func, flags, scope, false)
	}
	return nil
}
type anonymous_id_gen struct {
	sync.Mutex
	i int
}
func (a *anonymous_id_gen) gen() (id int) {
	a.Lock()
	defer a.Unlock()
	id = a.i
	a.i++
	return
}
var g_anon_gen anonymous_id_gen
func check_for_anon_type(t ast.Expr, flags decl_flags, s *scope) ast.Expr {
	if t == nil {
		return nil
	}
	var name string
	switch t.(type) {
	case *ast.StructType:
		name = fmt.Sprintf("$s_%d", g_anon_gen.gen())
	case *ast.InterfaceType:
		name = fmt.Sprintf("$i_%d", g_anon_gen.gen())
	}
	if name != "" {
		anonymify_ast(t, flags, s)
		d := new_decl_full(name, decl_type, flags, t, nil, -1, s)
		s.add_named_decl(d)
		return ast.NewIdent(name)
	}
	return t
}
func new_decl_full(name string, class decl_class, flags decl_flags, typ, v ast.Expr, vi int, s *scope) *decl {
	if name == "_" {
		return nil
	}
	d := new(decl)
	d.name = name
	d.class = class
	d.flags = flags
	d.typ = typ
	d.value = v
	d.value_index = vi
	d.scope = s
	d.children = ast_type_to_children(d.typ, flags, s)
	d.embedded = ast_type_to_embedded(d.typ)
	return d
}
func new_decl(name string, class decl_class, scope *scope) *decl {
	decl := new(decl)
	decl.name = name
	decl.class = class
	decl.value_index = -1
	decl.scope = scope
	return decl
}
func new_decl_var(name string, typ ast.Expr, value ast.Expr, vindex int, scope *scope) *decl {
	if name == "_" {
		return nil
	}
	decl := new(decl)
	decl.name = name
	decl.class = decl_var
	decl.typ = typ
	decl.value = value
	decl.value_index = vindex
	decl.scope = scope
	return decl
}
func method_of(d ast.Decl) string {
	if t, ok := d.(*ast.FuncDecl); ok {
		if t.Recv != nil {
			switch t := t.Recv.List[0].Type.(type) {
			case *ast.StarExpr:
				if se, ok := t.X.(*ast.SelectorExpr); ok {
					return se.Sel.Name
				}
				return t.X.(*ast.Ident).Name
			case *ast.Ident:
				return t.Name
			default:
				return ""
			}
		}
	}
	return ""
}
func (other *decl) deep_copy() *decl {
	d := new(decl)
	d.name = other.name
	d.class = other.class
	d.typ = other.typ
	d.value = other.value
	d.value_index = other.value_index
	d.children = make(map[string]*decl, len(other.children))
	for key, value := range other.children {
		d.children[key] = value
	}
	if other.embedded != nil {
		d.embedded = make([]ast.Expr, len(other.embedded))
		copy(d.embedded, other.embedded)
	}
	d.scope = other.scope
	return d
}
func (d *decl) clear_visited() {
	d.flags &^= decl_visited
}
func (d *decl) expand_or_replace(other *decl) {
	if d.class != decl_methods_stub && other.class != decl_methods_stub {
		d = other
		return
	}
	if d.class == decl_methods_stub {
		d.typ = other.typ
		d.class = other.class
	}
	if other.children != nil {
		for _, c := range other.children {
			d.add_child(c)
		}
	}
	if other.embedded != nil {
		d.embedded = other.embedded
		d.scope = other.scope
	}
}
func (d *decl) matches() bool {
	if strings.HasPrefix(d.name, "$") || d.class == decl_methods_stub {
		return false
	}
	return true
}
func (d *decl) pretty_print_type(out io.Writer) {
	switch d.class {
	case decl_type:
		switch d.typ.(type) {
		case *ast.StructType:
			fmt.Fprintf(out, "struct")
		case *ast.InterfaceType:
			fmt.Fprintf(out, "interface")
		default:
			if d.typ != nil {
				pretty_print_type_expr(out, d.typ)
			}
		}
	case decl_var:
		if d.typ != nil {
			pretty_print_type_expr(out, d.typ)
		}
	case decl_func:
		pretty_print_type_expr(out, d.typ)
	}
}
func (d *decl) add_child(cd *decl) {
	if d.children == nil {
		d.children = make(map[string]*decl)
	}
	d.children[cd.name] = cd
}
func check_for_builtin_funcs(typ *ast.Ident, c *ast.CallExpr, scope *scope) (ast.Expr, *scope) {
	if strings.HasPrefix(typ.Name, "func(") {
		if t, ok := c.Fun.(*ast.Ident); ok {
			switch t.Name {
			case "new":
				if len(c.Args) > 0 {
					e := new(ast.StarExpr)
					e.X = c.Args[0]
					return e, scope
				}
			case "make":
				if len(c.Args) > 0 {
					return c.Args[0], scope
				}
			case "append":
				if len(c.Args) > 0 {
					t, scope, _ := infer_type(c.Args[0], scope, -1)
					return t, scope
				}
			case "complex":
				return ast.NewIdent("complex"), g_universe_scope
			case "closed":
				return ast.NewIdent("bool"), g_universe_scope
			case "cap":
				return ast.NewIdent("int"), g_universe_scope
			case "copy":
				return ast.NewIdent("int"), g_universe_scope
			case "len":
				return ast.NewIdent("int"), g_universe_scope
			}
		}
	}
	return nil, nil
}
func func_return_type(f *ast.FuncType, index int) ast.Expr {
	if f.Results == nil {
		return nil
	}
	if index == -1 {
		return f.Results.List[0].Type
	}
	i := 0
	var field *ast.Field
	for _, field = range f.Results.List {
		if i >= index {
			return field.Type
		}
		if field.Names != nil {
			i += len(field.Names)
		} else {
			i++
		}
	}
	if i >= index {
		return field.Type
	}
	return nil
}
type type_path struct {
	pkg  string
	name string
}
func (tp *type_path) is_nil() bool {
	return tp.pkg == "" && tp.name == ""
}