示例#1
0
文件: decl.go 项目: JacobXie/gocode
// 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
}