Permalink
Fetching contributors…
Cannot retrieve contributors at this time
1473 lines (1330 sloc) 32.2 KB
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
// decl of decl_type class is a type alias
decl_alias
// 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_flags(d ast.Decl) decl_flags {
switch t := d.(type) {
case *ast.GenDecl:
switch t.Tok {
case token.TYPE:
if isAliasTypeSpec(t.Specs[0].(*ast.TypeSpec)) {
return decl_alias
}
}
}
return 0
}
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 && len(t.Recv.List) != 0 {
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.flags = other.flags
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) is_rangevar() bool {
return d.flags&decl_rangevar != 0
}
func (d *decl) is_alias() bool {
return d.flags&decl_alias != 0
}
func (d *decl) is_visited() bool {
return d.flags&decl_visited != 0
}
func (d *decl) set_visited() {
d.flags |= decl_visited
}
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 keep it as is
if d.class != decl_methods_stub && other.class != decl_methods_stub {
return
}
if d.class == decl_methods_stub {
d.typ = other.typ
d.class = other.class
d.flags = other.flags
}
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.is_visited() {
return nil, nil
}
decl.set_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.is_visited() {
return nil
}
decl.set_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.is_rangevar() {
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.is_visited() {
return nil, nil
}
d.set_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) type_dealias() *decl {
if d.is_visited() {
return nil
}
d.set_visited()
defer d.clear_visited()
dd := type_to_decl(d.typ, d.scope)
if dd != nil && dd.is_alias() {
return dd.type_dealias()
}
return dd
}
func (d *decl) find_child(name string) *decl {
// type aliases don't really have any children on their own, but they
// point to a different type, let's try to find one
if d.is_alias() {
dd := d.type_dealias()
if dd != nil {
return dd.find_child(name)
}
// note that type alias can also point to a type literal, something like
// type A = struct { A int }
// in this case we rely on "advance_to_struct_or_interface" below
}
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 {
if d.is_visited() {
return nil
}
d.set_visited()
defer d.clear_visited()
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)
}