func checkForBuiltinFuncs(typ *ast.Ident, c *ast.CallExpr) ast.Expr { if strings.HasPrefix(typ.Name(), "func(") { if t, ok := c.Fun.(*ast.Ident); ok { switch t.Name() { case "new": e := new(ast.StarExpr) e.X = c.Args[0] return e case "make": return c.Args[0] case "cmplx": return ast.NewIdent("complex") case "closed": return ast.NewIdent("bool") } } } return nil }
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": e := new(ast.StarExpr) e.X = c.Args[0] return e, scope case "make": return c.Args[0], scope case "append": return c.Args[0], scope case "cmplx": return ast.NewIdent("complex"), g_universe_scope case "closed": return ast.NewIdent("bool"), g_universe_scope } } } return nil, nil }
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 }
// 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 }
// 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 (ctx *TypeInferenceContext) inferType(v ast.Expr) (ast.Expr, bool, *Scope) { cc := *ctx cc.index = -1 switch t := v.(type) { case *ast.CompositeLit: return t.Type, true, ctx.scope case *ast.Ident: if d := ctx.scope.lookup(t.Name()); d != nil { // we don't check for DECL_MODULE here, because module itself // isn't a type, in a type context it always will be used together // with SelectorExpr like: os.Error, ast.TypeSpec, etc. // and SelectorExpr ignores type bool. typ, scope := d.InferType(ctx.ac) return typ, d.Class == DECL_TYPE, scope } //return t, true // probably a builtin case *ast.UnaryExpr: switch t.Op { case token.AND: // & makes sense only with values, don't even check for type it, _, scope := cc.inferType(t.X) if it == nil { break } e := new(ast.StarExpr) e.X = it return e, false, scope case token.ARROW: // <- makes sense only with values it, _, scope := cc.inferType(t.X) if it == nil { break } switch ctx.index { case -1, 0: return it.(*ast.ChanType).Value, false, scope case 1: // technically it's a value, but in case of index == 1 // it is always the last infer operation return ast.NewIdent("bool"), false, scope // TODO: return real built-in bool here } } case *ast.IndexExpr: // something[another] always returns a value and it works on a value too it, _, scope := cc.inferType(t.X) if it == nil { break } switch t := it.(type) { case *ast.ArrayType: return t.Elt, false, scope case *ast.MapType: switch ctx.index { case -1, 0: return t.Value, false, scope case 1: return ast.NewIdent("bool"), false, scope // TODO: return real built-in bool here } } case *ast.StarExpr: it, isType, scope := cc.inferType(t.X) if it == nil { break } if isType { // if it's a type, add * modifier, make it a 'pointer of' type e := new(ast.StarExpr) e.X = it return e, true, scope } else if s, ok := it.(*ast.StarExpr); ok { // if it's a pointer value, dereference pointer return s.X, false, scope } case *ast.CallExpr: it, _, scope := cc.inferType(t.Fun) if it == nil { break } switch ct := it.(type) { case *ast.FuncType: // in case if <here>() is a function type variable, we're making a // func call, resulting expr is always a value return funcReturnType(ct, ctx.index), false, scope case *ast.Ident: ty := checkForBuiltinFuncs(ct, t) if ty != nil { return ty, false, ctx.scope } return ct, false, ctx.scope default: // otherwise it's a type cast, and the result is a value too return ct, false, ctx.scope } case *ast.ParenExpr: it, isType, scope := cc.inferType(t.X) if it == nil { break } return it, isType, scope case *ast.SelectorExpr: it, _, scope := cc.inferType(t.X) if it == nil { break } var d *Decl switch it.(type) { case *ast.StructType, *ast.InterfaceType: d = NewDeclVar("tmp", it, nil, -1, scope) default: d = typeToDecl(it, scope, ctx.ac) } if d != nil { c := d.FindChildAndInEmbedded(t.Sel.Name(), ctx.ac) if c != nil { if c.Class == DECL_TYPE { // use foregnified module name t.X = ast.NewIdent(d.Name) return t, true, ctx.scope } else { typ, scope := c.InferType(ctx.ac) return typ, false, scope } } } 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, false, ctx.scope case *ast.TypeAssertExpr: if t.Type == nil { return cc.inferType(t.X) } switch ctx.index { case -1, 0: // converting a value to a different type, but return thing is a value return t.Type, false, ctx.scope case 1: return ast.NewIdent("bool"), false, ctx.scope // TODO: return real built-in bool here } case *ast.ArrayType, *ast.MapType, *ast.ChanType, *ast.FuncType: return t, true, ctx.scope default: _ = reflect.Typeof(v) //fmt.Println(ty) } return nil, false, nil }