package main import ( "bytes" "fmt" "go/ast" "go/token" "io" "reflect" "strings" "sync" ) // decl.class type decl_class int16 const ( decl_invalid = decl_class(-1 + iota) // these are in a sorted order decl_const decl_func decl_import decl_package decl_type decl_var // this one serves as a temporary type for those methods that were // declared before their actual owner 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_import: return "import" 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" // :D } panic("unreachable") } // decl.flags type decl_flags int16 const ( decl_foreign = decl_flags(1 << iota) // imported from another package // means that the decl is a part of the range statement // its type is inferred in a special way decl_rangevar // for preventing infinite recursions and loops in type inference code decl_visited ) //------------------------------------------------------------------------- // decl // // The most important data structure of the whole gocode project. It // describes a single declaration and its children. //------------------------------------------------------------------------- type decl struct { // Name starts with '$' if the declaration describes an anonymous type. // '$s_%d' for anonymous struct types // '$i_%d' for anonymous interface types name string typ ast.Expr class decl_class flags decl_flags // functions for interface type, fields+methods for struct type children map[string]*decl // embedded types embedded []ast.Expr // if the type is unknown at AST building time, I'm using these value ast.Expr // if it's a multiassignment and the Value is a CallExpr, it is being set // to an index into the return value tuple, otherwise it's a -1 value_index int // scope where this Decl was declared in (not its visibilty scope!) // Decl uses it for type inference 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 } // add anonymous field as a child (type embedding) 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 } //------------------------------------------------------------------------- // anonymous_id_gen // // ID generator for anonymous types (thread-safe) //------------------------------------------------------------------------- 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 } if ident, ok := t.X.(*ast.Ident); ok { return ident.Name } return "" 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) { // expand only if it's a methods stub, otherwise simply copy 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: // TODO: not used due to anonymify? fmt.Fprintf(out, "struct") case *ast.InterfaceType: // TODO: not used due to anonymify? 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": // TODO: fix it 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 } // TODO: // func recover() interface{} // func imag(c ComplexType) FloatType // func real(c ComplexType) FloatType } } 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 == "" } // 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 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 } func lookup_path(tp type_path, scope *scope) *decl { if tp.is_nil() { return nil } var decl *decl if tp.pkg != "" { decl = scope.lookup(tp.pkg) // return nil early if the package wasn't found but it's part // of the type specification if decl == nil { return nil } } if decl != nil { if tp.name != "" { return decl.find_child(tp.name) } else { return decl } } return scope.lookup(tp.name) } func lookup_pkg(tp type_path, scope *scope) string { if tp.is_nil() { return "" } if tp.pkg == "" { return "" } decl := scope.lookup(tp.pkg) if decl == nil { return "" } return decl.name } func type_to_decl(t ast.Expr, scope *scope) *decl { tp := get_type_path(t) d := lookup_path(tp, scope) if d != nil && d.class == decl_var { // weird variable declaration pointing to itself return nil } return d } func expr_to_decl(e ast.Expr, scope *scope) *decl { t, scope, _ := infer_type(e, scope, -1) return type_to_decl(t, scope) } //------------------------------------------------------------------------- // Type inference //------------------------------------------------------------------------- type type_predicate func(ast.Expr) bool func advance_to_type(pred type_predicate, v ast.Expr, scope *scope) (ast.Expr, *scope) { if pred(v) { return v, scope } decl := type_to_decl(v, scope) if decl == nil { return nil, nil } if decl.flags&decl_visited != 0 { return nil, nil } decl.flags |= decl_visited defer decl.clear_visited() return advance_to_type(pred, decl.typ, decl.scope) } func advance_to_struct_or_interface(decl *decl) *decl { if decl.flags&decl_visited != 0 { return nil } decl.flags |= decl_visited defer decl.clear_visited() if struct_interface_predicate(decl.typ) { return decl } decl = type_to_decl(decl.typ, decl.scope) if decl == nil { return nil } return advance_to_struct_or_interface(decl) } func struct_interface_predicate(v ast.Expr) bool { switch v.(type) { case *ast.StructType, *ast.InterfaceType: return true } return false } func chan_predicate(v ast.Expr) bool { _, ok := v.(*ast.ChanType) return ok } func index_predicate(v ast.Expr) bool { switch v.(type) { case *ast.ArrayType, *ast.MapType, *ast.Ellipsis: return true } return false } func star_predicate(v ast.Expr) bool { _, ok := v.(*ast.StarExpr) return ok } func func_predicate(v ast.Expr) bool { _, ok := v.(*ast.FuncType) return ok } func range_predicate(v ast.Expr) bool { switch t := v.(type) { case *ast.Ident: if t.Name == "string" { return true } case *ast.ArrayType, *ast.MapType, *ast.ChanType, *ast.Ellipsis: return true } return false } type anonymous_typer struct { flags decl_flags scope *scope } func (a *anonymous_typer) Visit(node ast.Node) ast.Visitor { switch t := node.(type) { case *ast.CompositeLit: t.Type = check_for_anon_type(t.Type, a.flags, a.scope) case *ast.MapType: t.Key = check_for_anon_type(t.Key, a.flags, a.scope) t.Value = check_for_anon_type(t.Value, a.flags, a.scope) case *ast.ArrayType: t.Elt = check_for_anon_type(t.Elt, a.flags, a.scope) case *ast.Ellipsis: t.Elt = check_for_anon_type(t.Elt, a.flags, a.scope) case *ast.ChanType: t.Value = check_for_anon_type(t.Value, a.flags, a.scope) case *ast.Field: t.Type = check_for_anon_type(t.Type, a.flags, a.scope) case *ast.CallExpr: t.Fun = check_for_anon_type(t.Fun, a.flags, a.scope) case *ast.ParenExpr: t.X = check_for_anon_type(t.X, a.flags, a.scope) case *ast.StarExpr: t.X = check_for_anon_type(t.X, a.flags, a.scope) case *ast.GenDecl: switch t.Tok { case token.VAR: for _, s := range t.Specs { vs := s.(*ast.ValueSpec) vs.Type = check_for_anon_type(vs.Type, a.flags, a.scope) } } } return a } func anonymify_ast(node ast.Node, flags decl_flags, scope *scope) { v := anonymous_typer{flags, scope} ast.Walk(&v, node) } // RETURNS: // - type expression which represents a full name of a type // - bool whether a type expression is actually a type (used internally) // - scope in which type makes sense func infer_type(v ast.Expr, scope *scope, index int) (ast.Expr, *scope, bool) { switch t := v.(type) { case *ast.CompositeLit: return t.Type, scope, true case *ast.Ident: if d := scope.lookup(t.Name); d != nil { if d.class == decl_package { return ast.NewIdent(t.Name), scope, false } typ, scope := d.infer_type() return typ, scope, d.class == decl_type } case *ast.UnaryExpr: switch t.Op { case token.AND: // &a makes sense only with values, don't even check for type it, s, _ := infer_type(t.X, scope, -1) if it == nil { break } e := new(ast.StarExpr) e.X = it return e, s, false case token.ARROW: // <-a makes sense only with values it, s, _ := infer_type(t.X, scope, -1) if it == nil { break } switch index { case -1, 0: it, s = advance_to_type(chan_predicate, it, s) return it.(*ast.ChanType).Value, s, false case 1: // technically it's a value, but in case of index == 1 // it is always the last infer operation return ast.NewIdent("bool"), g_universe_scope, false } case token.ADD, token.NOT, token.SUB, token.XOR: it, s, _ := infer_type(t.X, scope, -1) if it == nil { break } return it, s, false } case *ast.BinaryExpr: switch t.Op { case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ, token.LOR, token.LAND: // logic operations, the result is a bool, always return ast.NewIdent("bool"), g_universe_scope, false case token.ADD, token.SUB, token.MUL, token.QUO, token.OR, token.XOR, token.REM, token.AND, token.AND_NOT: // try X, then Y, they should be the same anyway it, s, _ := infer_type(t.X, scope, -1) if it == nil { it, s, _ = infer_type(t.Y, scope, -1) if it == nil { break } } return it, s, false case token.SHL, token.SHR: // try only X for shifts, Y is always uint it, s, _ := infer_type(t.X, scope, -1) if it == nil { break } return it, s, false } case *ast.IndexExpr: // something[another] always returns a value and it works on a value too it, s, _ := infer_type(t.X, scope, -1) if it == nil { break } it, s = advance_to_type(index_predicate, it, s) switch t := it.(type) { case *ast.ArrayType: return t.Elt, s, false case *ast.Ellipsis: return t.Elt, s, false case *ast.MapType: switch index { case -1, 0: return t.Value, s, false case 1: return ast.NewIdent("bool"), g_universe_scope, false } } case *ast.SliceExpr: // something[start : end] always returns a value it, s, _ := infer_type(t.X, scope, -1) if it == nil { break } it, s = advance_to_type(index_predicate, it, s) switch t := it.(type) { case *ast.ArrayType: e := new(ast.ArrayType) e.Elt = t.Elt return e, s, false } case *ast.StarExpr: it, s, is_type := infer_type(t.X, scope, -1) if it == nil { break } if is_type { // if it's a type, add * modifier, make it a 'pointer of' type e := new(ast.StarExpr) e.X = it return e, s, true } else { it, s := advance_to_type(star_predicate, it, s) if se, ok := it.(*ast.StarExpr); ok { return se.X, s, false } } case *ast.CallExpr: // this is a function call or a type cast: // myFunc(1,2,3) or int16(myvar) it, s, is_type := infer_type(t.Fun, scope, -1) if it == nil { break } if is_type { // a type cast return it, scope, false } else { // it must be a function call or a built-in function // first check for built-in if ct, ok := it.(*ast.Ident); ok { ty, s := check_for_builtin_funcs(ct, t, scope) if ty != nil { return ty, s, false } } // then check for an ordinary function call it, scope = advance_to_type(func_predicate, it, s) if ct, ok := it.(*ast.FuncType); ok { return func_return_type(ct, index), s, false } } case *ast.ParenExpr: it, s, is_type := infer_type(t.X, scope, -1) if it == nil { break } return it, s, is_type case *ast.SelectorExpr: it, s, _ := infer_type(t.X, scope, -1) if it == nil { break } if d := type_to_decl(it, s); d != nil { c := d.find_child_and_in_embedded(t.Sel.Name) if c != nil { if c.class == decl_type { return t, scope, true } else { typ, s := c.infer_type() return typ, s, false } } } case *ast.FuncLit: // it's a value, but I think most likely we don't even care, cause we can only // call it, and CallExpr uses the type itself to figure out return t.Type, scope, false case *ast.TypeAssertExpr: if t.Type == nil { return infer_type(t.X, scope, -1) } switch index { case -1, 0: // converting a value to a different type, but return thing is a value it, _, _ := infer_type(t.Type, scope, -1) return it, scope, false case 1: return ast.NewIdent("bool"), g_universe_scope, false } case *ast.ArrayType, *ast.MapType, *ast.ChanType, *ast.Ellipsis, *ast.FuncType, *ast.StructType, *ast.InterfaceType: return t, scope, true default: _ = reflect.TypeOf(v) //fmt.Println(ty) } return nil, nil, false } // Uses Value, ValueIndex and Scope to infer the type of this // declaration. Returns the type itself and the scope where this type // makes sense. func (d *decl) infer_type() (ast.Expr, *scope) { // special case for range vars if d.flags&decl_rangevar != 0 { var scope *scope d.typ, scope = infer_range_type(d.value, d.scope, d.value_index) return d.typ, scope } switch d.class { case decl_package: // package is handled specially in inferType return nil, nil case decl_type: return ast.NewIdent(d.name), d.scope } // shortcut if d.typ != nil && d.value == nil { return d.typ, d.scope } // prevent loops if d.flags&decl_visited != 0 { return nil, nil } d.flags |= decl_visited defer d.clear_visited() var scope *scope d.typ, scope, _ = infer_type(d.value, d.scope, d.value_index) return d.typ, scope } func (d *decl) find_child(name string) *decl { if d.flags&decl_visited != 0 { return nil } d.flags |= decl_visited defer d.clear_visited() if d.children != nil { if c, ok := d.children[name]; ok { return c } } decl := advance_to_struct_or_interface(d) if decl != nil && decl != d { return decl.find_child(name) } return nil } func (d *decl) find_child_and_in_embedded(name string) *decl { if d == nil { return nil } c := d.find_child(name) if c == nil { for _, e := range d.embedded { typedecl := type_to_decl(e, d.scope) c = typedecl.find_child_and_in_embedded(name) if c != nil { break } } } return c } // Special type inference for range statements. // [int], [int] := range [string] // [int], [value] := range [slice or array] // [key], [value] := range [map] // [value], [nil] := range [chan] func infer_range_type(e ast.Expr, sc *scope, valueindex int) (ast.Expr, *scope) { t, s, _ := infer_type(e, sc, -1) t, s = advance_to_type(range_predicate, t, s) if t != nil { var t1, t2 ast.Expr var s1, s2 *scope s1 = s s2 = s switch t := t.(type) { case *ast.Ident: // string if t.Name == "string" { t1 = ast.NewIdent("int") t2 = ast.NewIdent("rune") s1 = g_universe_scope s2 = g_universe_scope } else { t1, t2 = nil, nil } case *ast.ArrayType: t1 = ast.NewIdent("int") s1 = g_universe_scope t2 = t.Elt case *ast.Ellipsis: t1 = ast.NewIdent("int") s1 = g_universe_scope t2 = t.Elt case *ast.MapType: t1 = t.Key t2 = t.Value case *ast.ChanType: t1 = t.Value t2 = nil default: t1, t2 = nil, nil } switch valueindex { case 0: return t1, s1 case 1: return t2, s2 } } return nil, nil } //------------------------------------------------------------------------- // Pretty printing //------------------------------------------------------------------------- func get_array_len(e ast.Expr) string { switch t := e.(type) { case *ast.BasicLit: return string(t.Value) case *ast.Ellipsis: return "..." } return "" } func pretty_print_type_expr(out io.Writer, e ast.Expr) { switch t := e.(type) { case *ast.StarExpr: fmt.Fprintf(out, "*") pretty_print_type_expr(out, t.X) case *ast.Ident: if strings.HasPrefix(t.Name, "$") { // beautify anonymous types switch t.Name[1] { case 's': fmt.Fprintf(out, "struct") case 'i': // ok, in most cases anonymous interface is an // empty interface, I'll just pretend that // it's always true fmt.Fprintf(out, "interface{}") } } else if !*g_debug && strings.HasPrefix(t.Name, "#") { fmt.Fprintf(out, t.Name[1:]) } else if !*g_debug && strings.HasPrefix(t.Name, "!") { // these are full package names for disambiguating and pretty // printing packages withing packages, e.g. // !go/ast!ast vs. !github.com/nsf/my/ast!ast // another ugly hack, if people are punished in hell for ugly hacks // I'm screwed... fmt.Fprintf(out, t.Name[strings.LastIndex(t.Name, "!")+1:]) } else { fmt.Fprintf(out, t.Name) } case *ast.ArrayType: al := "" if t.Len != nil { al = get_array_len(t.Len) } if al != "" { fmt.Fprintf(out, "[%s]", al) } else { fmt.Fprintf(out, "[]") } pretty_print_type_expr(out, t.Elt) case *ast.SelectorExpr: pretty_print_type_expr(out, t.X) fmt.Fprintf(out, ".%s", t.Sel.Name) case *ast.FuncType: fmt.Fprintf(out, "func(") pretty_print_func_field_list(out, t.Params) fmt.Fprintf(out, ")") buf := bytes.NewBuffer(make([]byte, 0, 256)) nresults := pretty_print_func_field_list(buf, t.Results) if nresults > 0 { results := buf.String() if strings.IndexAny(results, ", ") != -1 { results = "(" + results + ")" } fmt.Fprintf(out, " %s", results) } case *ast.MapType: fmt.Fprintf(out, "map[") pretty_print_type_expr(out, t.Key) fmt.Fprintf(out, "]") pretty_print_type_expr(out, t.Value) case *ast.InterfaceType: fmt.Fprintf(out, "interface{}") case *ast.Ellipsis: fmt.Fprintf(out, "...") pretty_print_type_expr(out, t.Elt) case *ast.StructType: fmt.Fprintf(out, "struct") case *ast.ChanType: switch t.Dir { case ast.RECV: fmt.Fprintf(out, "<-chan ") case ast.SEND: fmt.Fprintf(out, "chan<- ") case ast.SEND | ast.RECV: fmt.Fprintf(out, "chan ") } pretty_print_type_expr(out, t.Value) case *ast.ParenExpr: fmt.Fprintf(out, "(") pretty_print_type_expr(out, t.X) fmt.Fprintf(out, ")") case *ast.BadExpr: // TODO: probably I should check that in a separate function // and simply discard declarations with BadExpr as a part of their // type default: // the element has some weird type, just ignore it } } func pretty_print_func_field_list(out io.Writer, f *ast.FieldList) int { count := 0 if f == nil { return count } for i, field := range f.List { // names if field.Names != nil { hasNonblank := false for j, name := range field.Names { if name.Name != "?" { hasNonblank = true fmt.Fprintf(out, "%s", name.Name) if j != len(field.Names)-1 { fmt.Fprintf(out, ", ") } } count++ } if hasNonblank { fmt.Fprintf(out, " ") } } else { count++ } // type pretty_print_type_expr(out, field.Type) // , if i != len(f.List)-1 { fmt.Fprintf(out, ", ") } } return count } func ast_decl_names(d ast.Decl) []*ast.Ident { var names []*ast.Ident switch t := d.(type) { case *ast.GenDecl: switch t.Tok { case token.CONST: c := t.Specs[0].(*ast.ValueSpec) names = make([]*ast.Ident, len(c.Names)) for i, name := range c.Names { names[i] = name } case token.TYPE: t := t.Specs[0].(*ast.TypeSpec) names = make([]*ast.Ident, 1) names[0] = t.Name case token.VAR: v := t.Specs[0].(*ast.ValueSpec) names = make([]*ast.Ident, len(v.Names)) for i, name := range v.Names { names[i] = name } } case *ast.FuncDecl: names = make([]*ast.Ident, 1) names[0] = t.Name } return names } func ast_decl_values(d ast.Decl) []ast.Expr { // TODO: CONST values here too switch t := d.(type) { case *ast.GenDecl: switch t.Tok { case token.VAR: v := t.Specs[0].(*ast.ValueSpec) if v.Values != nil { return v.Values } } } return nil } func ast_decl_split(d ast.Decl) []ast.Decl { var decls []ast.Decl if t, ok := d.(*ast.GenDecl); ok { decls = make([]ast.Decl, len(t.Specs)) for i, s := range t.Specs { decl := new(ast.GenDecl) *decl = *t decl.Specs = make([]ast.Spec, 1) decl.Specs[0] = s decls[i] = decl } } else { decls = make([]ast.Decl, 1) decls[0] = d } return decls } //------------------------------------------------------------------------- // decl_pack //------------------------------------------------------------------------- type decl_pack struct { names []*ast.Ident typ ast.Expr values []ast.Expr } type foreach_decl_struct struct { decl_pack decl ast.Decl } func (f *decl_pack) value(i int) ast.Expr { if f.values == nil { return nil } if len(f.values) > 1 { return f.values[i] } return f.values[0] } func (f *decl_pack) value_index(i int) (v ast.Expr, vi int) { // default: nil value v = nil vi = -1 if f.values != nil { // A = B, if there is only one name, the value is solo too if len(f.names) == 1 { return f.values[0], -1 } if len(f.values) > 1 { // in case if there are multiple values, it's a usual // multiassignment if i >= len(f.values) { i = len(f.values) - 1 } v = f.values[i] } else { // in case if there is one value, but many names, it's // a tuple unpack.. use index here v = f.values[0] vi = i } } return } func (f *decl_pack) type_value_index(i int) (ast.Expr, ast.Expr, int) { if f.typ != nil { // If there is a type, we don't care about value, just return the type // and zero value. return f.typ, nil, -1 } // And otherwise we simply return nil type and a valid value for later inferring. v, vi := f.value_index(i) return nil, v, vi } type foreach_decl_func func(data *foreach_decl_struct) func foreach_decl(decl ast.Decl, do foreach_decl_func) { decls := ast_decl_split(decl) var data foreach_decl_struct for _, decl := range decls { if !ast_decl_convertable(decl) { continue } data.names = ast_decl_names(decl) data.typ = ast_decl_type(decl) data.values = ast_decl_values(decl) data.decl = decl do(&data) } } //------------------------------------------------------------------------- // Built-in declarations //------------------------------------------------------------------------- var g_universe_scope = new_scope(nil) func init() { builtin := ast.NewIdent("built-in") add_type := func(name string) { d := new_decl(name, decl_type, g_universe_scope) d.typ = builtin g_universe_scope.add_named_decl(d) } add_type("bool") add_type("byte") add_type("complex64") add_type("complex128") add_type("float32") add_type("float64") add_type("int8") add_type("int16") add_type("int32") add_type("int64") add_type("string") add_type("uint8") add_type("uint16") add_type("uint32") add_type("uint64") add_type("int") add_type("uint") add_type("uintptr") add_type("rune") add_const := func(name string) { d := new_decl(name, decl_const, g_universe_scope) d.typ = builtin g_universe_scope.add_named_decl(d) } add_const("true") add_const("false") add_const("iota") add_const("nil") add_func := func(name, typ string) { d := new_decl(name, decl_func, g_universe_scope) d.typ = ast.NewIdent(typ) g_universe_scope.add_named_decl(d) } add_func("append", "func([]type, ...type) []type") add_func("cap", "func(container) int") add_func("close", "func(channel)") add_func("complex", "func(real, imag) complex") add_func("copy", "func(dst, src)") add_func("delete", "func(map[typeA]typeB, typeA)") add_func("imag", "func(complex)") add_func("len", "func(container) int") add_func("make", "func(type, len[, cap]) type") add_func("new", "func(type) *type") add_func("panic", "func(interface{})") add_func("print", "func(...interface{})") add_func("println", "func(...interface{})") add_func("real", "func(complex)") add_func("recover", "func() interface{}") // built-in error interface d := new_decl("error", decl_type, g_universe_scope) d.typ = &ast.InterfaceType{} d.children = make(map[string]*decl) d.children["Error"] = new_decl("Error", decl_func, g_universe_scope) d.children["Error"].typ = &ast.FuncType{ Results: &ast.FieldList{ List: []*ast.Field{ { Type: ast.NewIdent("string"), }, }, }, } g_universe_scope.add_named_decl(d) }