func (tc *typechecker) resolve(obj *ast.Object) {
	// check for declaration cycles
	if tc.cyclemap[obj] {
		tc.Errorf(objPos(obj), "illegal cycle in declaration of %s", obj.Name)
		obj.Kind = ast.Bad
		return
	}
	tc.cyclemap[obj] = true
	defer func() {
		tc.cyclemap[obj] = false, false
	}()

	// resolve non-type objects
	typ := obj.Type
	if typ == nil {
		switch obj.Kind {
		case ast.Bad:
			// ignore

		case ast.Con:
			tc.declConst(obj)

		case ast.Var:
			tc.declVar(obj)
			//obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)

		case ast.Fun:
			obj.Type = ast.NewType(ast.Function)
			t := obj.Decl.(*ast.FuncDecl).Type
			tc.declSignature(obj.Type, nil, t.Params, t.Results)

		default:
			// type objects have non-nil types when resolve is called
			if debug {
				fmt.Printf("kind = %s\n", obj.Kind)
			}
			panic("unreachable")
		}
		return
	}

	// resolve type objects
	if typ.Form == ast.Unresolved {
		tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)

		// provide types for all methods
		for _, obj := range typ.Scope.Objects {
			if obj.Kind == ast.Fun {
				assert(obj.Type == nil)
				obj.Type = ast.NewType(ast.Method)
				f := obj.Decl.(*ast.FuncDecl)
				t := f.Type
				tc.declSignature(obj.Type, f.Recv, t.Params, t.Results)
			}
		}
	}
}
func (tc *typechecker) declGlobal(global ast.Decl) {
	switch d := global.(type) {
	case *ast.BadDecl:
		// ignore

	case *ast.GenDecl:
		iota := 0
		var prev *ast.ValueSpec
		for _, spec := range d.Specs {
			switch s := spec.(type) {
			case *ast.ImportSpec:
				// TODO(gri) imports go into file scope
			case *ast.ValueSpec:
				switch d.Tok {
				case token.CONST:
					if s.Values == nil {
						// create a new spec with type and values from the previous one
						if prev != nil {
							s = &ast.ValueSpec{s.Doc, s.Names, prev.Type, prev.Values, s.Comment}
						} else {
							// TODO(gri) this should probably go into the const decl code
							tc.Errorf(s.Pos(), "missing initializer for const %s", s.Names[0].Name)
						}
					}
					for _, name := range s.Names {
						tc.decl(ast.Con, name, s, iota)
					}
				case token.VAR:
					for _, name := range s.Names {
						tc.decl(ast.Var, name, s, 0)
					}
				default:
					panic("unreachable")
				}
				prev = s
				iota++
			case *ast.TypeSpec:
				obj := tc.decl(ast.Typ, s.Name, s, 0)
				// give all type objects an unresolved type so
				// that we can collect methods in the type scope
				typ := ast.NewType(ast.Unresolved)
				obj.Type = typ
				typ.Obj = obj
			default:
				panic("unreachable")
			}
		}

	case *ast.FuncDecl:
		if d.Recv == nil {
			tc.decl(ast.Fun, d.Name, d, 0)
		}

	default:
		panic("unreachable")
	}
}
func ExprType(e0 ast.Expr, s *Stack) (t *ast.Type) {
	t = ast.NewType(ast.Basic)
	switch e := e0.(type) {
	case *ast.BasicLit:
		switch e.Kind {
		case token.STRING:
			t.N = ast.String
		default:
			panic(fmt.Sprintf("I don't handle basic literals such as %s", e))
		}
	case *ast.CallExpr:
		switch fn := e.Fun.(type) {
		case *ast.Ident:
			switch fn.Name {
			case "println":
				return ast.NewType(ast.Tuple)
			case "print":
				return ast.NewType(ast.Tuple)
			default:
				ftype := s.Lookup(fn.Name).Type()
				switch ftype.N {
				case 0:
					// This is a function with no return value: easy!
					return ast.NewType(ast.Tuple)
				case 1:
					return ftype.Params.Objects[0].Type
				default:
					panic("I don't yet do multiple return types...")
				}
			}
		default:
			panic(fmt.Sprintf("Can't handle function of weird type %T", e.Fun))
		}
	case *ast.Ident:
		return s.Lookup(e.Name).Type()
	default:
		panic(fmt.Sprintf("I can't find type of expression %s of type %T\n", e0, e0))
	}
	return
}
func TypeExpression(e ast.Expr) (t *ast.Type) {
	switch e := e.(type) {
	case *ast.Ident:
		switch e.Name {
		case "string":
			t = ast.NewType(ast.Basic)
			t.N = ast.String
			return
		default:
			panic("I don't understand type " + e.Name)
		}
	default:
		panic(fmt.Sprintf("I can't understand type expression %s of type %T\n", e, e))
	}
	panic(fmt.Sprintf("I don't understand the type expression %s", e))
}
func init() {
	Universe = ast.NewScope(nil)

	// basic types
	for n, name := range ast.BasicTypes {
		typ := ast.NewType(ast.Basic)
		typ.N = n
		obj := ast.NewObj(ast.Typ, name)
		obj.Type = typ
		typ.Obj = obj
		def(obj)
	}

	// built-in functions
	// TODO(gri) implement this
}
Beispiel #6
0
func (v *CompileVisitor) FunctionPrologue(fn *ast.FuncDecl) {
	v.Stack = v.Stack.New(fn.Name.Name)
	ftype := ast.NewType(ast.Function)
	ftype.N = uint(fn.Type.Results.NumFields())
	ftype.Params = ast.NewScope(nil)
	fmt.Println("Working on function", fn.Name.Name)
	if fn.Type.Results != nil {
		resultnum := 0
		for _, resultfield := range fn.Type.Results.List {
			names := []string{"_"}
			if resultfield.Names != nil {
				names = []string{}
				for _, i := range resultfield.Names {
					names = append(names, i.Name)
				}
			}
			t := TypeExpression(resultfield.Type)
			for _, n := range names {
				ftype.Params.Insert(&ast.Object{ast.Fun, n, t, resultfield, 0})
				resultnum++
				v.Stack.DefineVariable(n, t, fmt.Sprintf("return_value_%d", resultnum))

				// The return values are actually allocated elsewhere... here
				// we just need to define the function type properly so it
				// gets called properly.
			}
		}
	}
	fmt.Println("Stack size after results is", v.Stack.Size)
	v.Stack.ReturnSize = v.Stack.Size
	// The arguments are pushed last argument first, so that eventually
	// the types of the "later" arguments can depend on the first
	// arguments, which seems nice to me.
	for pi := len(fn.Type.Params.List) - 1; pi >= 0; pi-- {
		paramfield := fn.Type.Params.List[pi]
		names := []string{"_"}
		if paramfield.Names != nil {
			names = []string{}
			for _, i := range paramfield.Names {
				names = append(names, i.Name)
			}
		}
		t := TypeExpression(paramfield.Type)
		for i := len(names) - 1; i >= 0; i-- {
			n := names[i]
			ftype.Params.Insert(&ast.Object{ast.Fun, n, t, paramfield, 0})
			v.Stack.DefineVariable(n, t)

			// The function parameters are actually allocated
			// elsewhere... here we just need to define the function type
			// properly so it gets called properly.
		}
	}
	fmt.Println("Stack size after params is", v.Stack.Size)
	v.Stack.DefineVariable("return", IntType)
	fmt.Println("Stack size after return is", v.Stack.Size)
	v.Stack = v.Stack.New("_")
	DefineGlobal(fn.Name.Name, ftype)
	// symbol for the start name
	pos := myfiles.Position(fn.Pos())
	v.Append(x86.Commented(x86.GlobalSymbol("main_"+fn.Name.Name),
		fmt.Sprint(pos.Filename, ": line ", pos.Line)))
	// If we had arguments, we'd want to swap them with the return
	// address here...
}
func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Type) {
	x = unparen(x)

	// type name
	if t, isIdent := x.(*ast.Ident); isIdent {
		obj := tc.find(t)

		if obj.Kind != ast.Typ {
			tc.Errorf(t.Pos(), "%s is not a type", t.Name)
			if def == nil {
				typ = ast.NewType(ast.BadType)
			} else {
				typ = def
				typ.Form = ast.BadType
			}
			typ.Expr = x
			return
		}

		if !ref {
			tc.resolve(obj) // check for cycles even if type resolved
		}
		typ = obj.Type

		if def != nil {
			// new type declaration: copy type structure
			def.Form = typ.Form
			def.N = typ.N
			def.Key, def.Elt = typ.Key, typ.Elt
			def.Params = typ.Params
			def.Expr = x
			typ = def
		}
		return
	}

	// type literal
	typ = def
	if typ == nil {
		typ = ast.NewType(ast.BadType)
	}
	typ.Expr = x

	switch t := x.(type) {
	case *ast.SelectorExpr:
		if debug {
			fmt.Println("qualified identifier unimplemented")
		}
		typ.Form = ast.BadType

	case *ast.StarExpr:
		typ.Form = ast.Pointer
		typ.Elt = tc.typeFor(nil, t.X, true)

	case *ast.ArrayType:
		if t.Len != nil {
			typ.Form = ast.Array
			// TODO(gri) compute the real length
			// (this may call resolve recursively)
			(*typ).N = 42
		} else {
			typ.Form = ast.Slice
		}
		typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil)

	case *ast.StructType:
		typ.Form = ast.Struct
		tc.declFields(typ.Scope, t.Fields, false)

	case *ast.FuncType:
		typ.Form = ast.Function
		tc.declSignature(typ, nil, t.Params, t.Results)

	case *ast.InterfaceType:
		typ.Form = ast.Interface
		tc.declFields(typ.Scope, t.Methods, true)

	case *ast.MapType:
		typ.Form = ast.Map
		typ.Key = tc.typeFor(nil, t.Key, true)
		typ.Elt = tc.typeFor(nil, t.Value, true)

	case *ast.ChanType:
		typ.Form = ast.Channel
		typ.N = uint(t.Dir)
		typ.Elt = tc.typeFor(nil, t.Value, true)

	default:
		if debug {
			fmt.Printf("x is %T\n", x)
		}
		panic("unreachable")
	}

	return
}
Beispiel #8
0
		}
	default:
		panic(fmt.Sprintf("I don't know how to pop type %s", t.Form))
	}
	return
}

func SizeOnStack(t *ast.Type) (out int) {
	out = TypeToSize(t)
	if out&3 != 0 {
		return 4 * (out/4 + 1)
	}
	return
}

var IntType *ast.Type = ast.NewType(ast.Basic)
var StringType *ast.Type = ast.NewType(ast.Basic)

func init() {
	IntType.N = ast.Int
	StringType.N = ast.String
}

func PrettyType(t *ast.Type) string {
	switch t.Form {
	case ast.Tuple:
		out := "("
		for _, o := range t.Params.Objects {
			if out != "(" {
				out += ", "
			}