Exemple #1
0
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
}
Exemple #2
0
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
}
Exemple #3
0
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
}
Exemple #4
0
// 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
}
Exemple #5
0
// 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
}