diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libgo/go/exp/eval/type.go | |
download | cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2 cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libgo/go/exp/eval/type.go')
-rw-r--r-- | libgo/go/exp/eval/type.go | 1252 |
1 files changed, 1252 insertions, 0 deletions
diff --git a/libgo/go/exp/eval/type.go b/libgo/go/exp/eval/type.go new file mode 100644 index 000000000..3f272ce4b --- /dev/null +++ b/libgo/go/exp/eval/type.go @@ -0,0 +1,1252 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package eval + +import ( + "big" + "go/ast" + "go/token" + "log" + "reflect" + "sort" + "unsafe" // For Sizeof +) + + +// XXX(Spec) The type compatibility section is very confusing because +// it makes it seem like there are three distinct types of +// compatibility: plain compatibility, assignment compatibility, and +// comparison compatibility. As I understand it, there's really only +// assignment compatibility and comparison and conversion have some +// restrictions and have special meaning in some cases where the types +// are not otherwise assignment compatible. The comparison +// compatibility section is almost all about the semantics of +// comparison, not the type checking of it, so it would make much more +// sense in the comparison operators section. The compatibility and +// assignment compatibility sections should be rolled into one. + +type Type interface { + // compat returns whether this type is compatible with another + // type. If conv is false, this is normal compatibility, + // where two named types are compatible only if they are the + // same named type. If conv if true, this is conversion + // compatibility, where two named types are conversion + // compatible if their definitions are conversion compatible. + // + // TODO(austin) Deal with recursive types + compat(o Type, conv bool) bool + // lit returns this type's literal. If this is a named type, + // this is the unnamed underlying type. Otherwise, this is an + // identity operation. + lit() Type + // isBoolean returns true if this is a boolean type. + isBoolean() bool + // isInteger returns true if this is an integer type. + isInteger() bool + // isFloat returns true if this is a floating type. + isFloat() bool + // isIdeal returns true if this is an ideal int or float. + isIdeal() bool + // Zero returns a new zero value of this type. + Zero() Value + // String returns the string representation of this type. + String() string + // The position where this type was defined, if any. + Pos() token.Pos +} + +type BoundedType interface { + Type + // minVal returns the smallest value of this type. + minVal() *big.Rat + // maxVal returns the largest value of this type. + maxVal() *big.Rat +} + +var universePos = token.NoPos + +/* + * Type array maps. These are used to memoize composite types. + */ + +type typeArrayMapEntry struct { + key []Type + v interface{} + next *typeArrayMapEntry +} + +type typeArrayMap map[uintptr]*typeArrayMapEntry + +func hashTypeArray(key []Type) uintptr { + hash := uintptr(0) + for _, t := range key { + hash = hash * 33 + if t == nil { + continue + } + addr := reflect.NewValue(t).(*reflect.PtrValue).Get() + hash ^= addr + } + return hash +} + +func newTypeArrayMap() typeArrayMap { return make(map[uintptr]*typeArrayMapEntry) } + +func (m typeArrayMap) Get(key []Type) interface{} { + ent, ok := m[hashTypeArray(key)] + if !ok { + return nil + } + +nextEnt: + for ; ent != nil; ent = ent.next { + if len(key) != len(ent.key) { + continue + } + for i := 0; i < len(key); i++ { + if key[i] != ent.key[i] { + continue nextEnt + } + } + // Found it + return ent.v + } + + return nil +} + +func (m typeArrayMap) Put(key []Type, v interface{}) interface{} { + hash := hashTypeArray(key) + ent := m[hash] + + new := &typeArrayMapEntry{key, v, ent} + m[hash] = new + return v +} + +/* + * Common type + */ + +type commonType struct{} + +func (commonType) isBoolean() bool { return false } + +func (commonType) isInteger() bool { return false } + +func (commonType) isFloat() bool { return false } + +func (commonType) isIdeal() bool { return false } + +func (commonType) Pos() token.Pos { return token.NoPos } + +/* + * Bool + */ + +type boolType struct { + commonType +} + +var BoolType = universe.DefineType("bool", universePos, &boolType{}) + +func (t *boolType) compat(o Type, conv bool) bool { + _, ok := o.lit().(*boolType) + return ok +} + +func (t *boolType) lit() Type { return t } + +func (t *boolType) isBoolean() bool { return true } + +func (boolType) String() string { + // Use angle brackets as a convention for printing the + // underlying, unnamed type. This should only show up in + // debug output. + return "<bool>" +} + +func (t *boolType) Zero() Value { + res := boolV(false) + return &res +} + +/* + * Uint + */ + +type uintType struct { + commonType + + // 0 for architecture-dependent types + Bits uint + // true for uintptr, false for all others + Ptr bool + name string +} + +var ( + Uint8Type = universe.DefineType("uint8", universePos, &uintType{commonType{}, 8, false, "uint8"}) + Uint16Type = universe.DefineType("uint16", universePos, &uintType{commonType{}, 16, false, "uint16"}) + Uint32Type = universe.DefineType("uint32", universePos, &uintType{commonType{}, 32, false, "uint32"}) + Uint64Type = universe.DefineType("uint64", universePos, &uintType{commonType{}, 64, false, "uint64"}) + + UintType = universe.DefineType("uint", universePos, &uintType{commonType{}, 0, false, "uint"}) + UintptrType = universe.DefineType("uintptr", universePos, &uintType{commonType{}, 0, true, "uintptr"}) +) + +func (t *uintType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*uintType) + return ok && t == t2 +} + +func (t *uintType) lit() Type { return t } + +func (t *uintType) isInteger() bool { return true } + +func (t *uintType) String() string { return "<" + t.name + ">" } + +func (t *uintType) Zero() Value { + switch t.Bits { + case 0: + if t.Ptr { + res := uintptrV(0) + return &res + } else { + res := uintV(0) + return &res + } + case 8: + res := uint8V(0) + return &res + case 16: + res := uint16V(0) + return &res + case 32: + res := uint32V(0) + return &res + case 64: + res := uint64V(0) + return &res + } + panic("unexpected uint bit count") +} + +func (t *uintType) minVal() *big.Rat { return big.NewRat(0, 1) } + +func (t *uintType) maxVal() *big.Rat { + bits := t.Bits + if bits == 0 { + if t.Ptr { + bits = uint(8 * unsafe.Sizeof(uintptr(0))) + } else { + bits = uint(8 * unsafe.Sizeof(uint(0))) + } + } + numer := big.NewInt(1) + numer.Lsh(numer, bits) + numer.Sub(numer, idealOne) + return new(big.Rat).SetInt(numer) +} + +/* + * Int + */ + +type intType struct { + commonType + + // XXX(Spec) Numeric types: "There is also a set of + // architecture-independent basic numeric types whose size + // depends on the architecture." Should that be + // architecture-dependent? + + // 0 for architecture-dependent types + Bits uint + name string +} + +var ( + Int8Type = universe.DefineType("int8", universePos, &intType{commonType{}, 8, "int8"}) + Int16Type = universe.DefineType("int16", universePos, &intType{commonType{}, 16, "int16"}) + Int32Type = universe.DefineType("int32", universePos, &intType{commonType{}, 32, "int32"}) + Int64Type = universe.DefineType("int64", universePos, &intType{commonType{}, 64, "int64"}) + + IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"}) +) + +func (t *intType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*intType) + return ok && t == t2 +} + +func (t *intType) lit() Type { return t } + +func (t *intType) isInteger() bool { return true } + +func (t *intType) String() string { return "<" + t.name + ">" } + +func (t *intType) Zero() Value { + switch t.Bits { + case 8: + res := int8V(0) + return &res + case 16: + res := int16V(0) + return &res + case 32: + res := int32V(0) + return &res + case 64: + res := int64V(0) + return &res + + case 0: + res := intV(0) + return &res + } + panic("unexpected int bit count") +} + +func (t *intType) minVal() *big.Rat { + bits := t.Bits + if bits == 0 { + bits = uint(8 * unsafe.Sizeof(int(0))) + } + numer := big.NewInt(-1) + numer.Lsh(numer, bits-1) + return new(big.Rat).SetInt(numer) +} + +func (t *intType) maxVal() *big.Rat { + bits := t.Bits + if bits == 0 { + bits = uint(8 * unsafe.Sizeof(int(0))) + } + numer := big.NewInt(1) + numer.Lsh(numer, bits-1) + numer.Sub(numer, idealOne) + return new(big.Rat).SetInt(numer) +} + +/* + * Ideal int + */ + +type idealIntType struct { + commonType +} + +var IdealIntType Type = &idealIntType{} + +func (t *idealIntType) compat(o Type, conv bool) bool { + _, ok := o.lit().(*idealIntType) + return ok +} + +func (t *idealIntType) lit() Type { return t } + +func (t *idealIntType) isInteger() bool { return true } + +func (t *idealIntType) isIdeal() bool { return true } + +func (t *idealIntType) String() string { return "ideal integer" } + +func (t *idealIntType) Zero() Value { return &idealIntV{idealZero} } + +/* + * Float + */ + +type floatType struct { + commonType + + // 0 for architecture-dependent type + Bits uint + + name string +} + +var ( + Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"}) + Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"}) +) + +func (t *floatType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*floatType) + return ok && t == t2 +} + +func (t *floatType) lit() Type { return t } + +func (t *floatType) isFloat() bool { return true } + +func (t *floatType) String() string { return "<" + t.name + ">" } + +func (t *floatType) Zero() Value { + switch t.Bits { + case 32: + res := float32V(0) + return &res + case 64: + res := float64V(0) + return &res + } + panic("unexpected float bit count") +} + +var maxFloat32Val *big.Rat +var maxFloat64Val *big.Rat +var minFloat32Val *big.Rat +var minFloat64Val *big.Rat + +func (t *floatType) minVal() *big.Rat { + bits := t.Bits + switch bits { + case 32: + return minFloat32Val + case 64: + return minFloat64Val + } + log.Panicf("unexpected floating point bit count: %d", bits) + panic("unreachable") +} + +func (t *floatType) maxVal() *big.Rat { + bits := t.Bits + switch bits { + case 32: + return maxFloat32Val + case 64: + return maxFloat64Val + } + log.Panicf("unexpected floating point bit count: %d", bits) + panic("unreachable") +} + +/* + * Ideal float + */ + +type idealFloatType struct { + commonType +} + +var IdealFloatType Type = &idealFloatType{} + +func (t *idealFloatType) compat(o Type, conv bool) bool { + _, ok := o.lit().(*idealFloatType) + return ok +} + +func (t *idealFloatType) lit() Type { return t } + +func (t *idealFloatType) isFloat() bool { return true } + +func (t *idealFloatType) isIdeal() bool { return true } + +func (t *idealFloatType) String() string { return "ideal float" } + +func (t *idealFloatType) Zero() Value { return &idealFloatV{big.NewRat(0, 1)} } + +/* + * String + */ + +type stringType struct { + commonType +} + +var StringType = universe.DefineType("string", universePos, &stringType{}) + +func (t *stringType) compat(o Type, conv bool) bool { + _, ok := o.lit().(*stringType) + return ok +} + +func (t *stringType) lit() Type { return t } + +func (t *stringType) String() string { return "<string>" } + +func (t *stringType) Zero() Value { + res := stringV("") + return &res +} + +/* + * Array + */ + +type ArrayType struct { + commonType + Len int64 + Elem Type +} + +var arrayTypes = make(map[int64]map[Type]*ArrayType) + +// Two array types are identical if they have identical element types +// and the same array length. + +func NewArrayType(len int64, elem Type) *ArrayType { + ts, ok := arrayTypes[len] + if !ok { + ts = make(map[Type]*ArrayType) + arrayTypes[len] = ts + } + t, ok := ts[elem] + if !ok { + t = &ArrayType{commonType{}, len, elem} + ts[elem] = t + } + return t +} + +func (t *ArrayType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*ArrayType) + if !ok { + return false + } + return t.Len == t2.Len && t.Elem.compat(t2.Elem, conv) +} + +func (t *ArrayType) lit() Type { return t } + +func (t *ArrayType) String() string { return "[]" + t.Elem.String() } + +func (t *ArrayType) Zero() Value { + res := arrayV(make([]Value, t.Len)) + // TODO(austin) It's unfortunate that each element is + // separately heap allocated. We could add ZeroArray to + // everything, though that doesn't help with multidimensional + // arrays. Or we could do something unsafe. We'll have this + // same problem with structs. + for i := int64(0); i < t.Len; i++ { + res[i] = t.Elem.Zero() + } + return &res +} + +/* + * Struct + */ + +type StructField struct { + Name string + Type Type + Anonymous bool +} + +type StructType struct { + commonType + Elems []StructField +} + +var structTypes = newTypeArrayMap() + +// Two struct types are identical if they have the same sequence of +// fields, and if corresponding fields have the same names and +// identical types. Two anonymous fields are considered to have the +// same name. + +func NewStructType(fields []StructField) *StructType { + // Start by looking up just the types + fts := make([]Type, len(fields)) + for i, f := range fields { + fts[i] = f.Type + } + tMapI := structTypes.Get(fts) + if tMapI == nil { + tMapI = structTypes.Put(fts, make(map[string]*StructType)) + } + tMap := tMapI.(map[string]*StructType) + + // Construct key for field names + key := "" + for _, f := range fields { + // XXX(Spec) It's not clear if struct { T } and struct + // { T T } are either identical or compatible. The + // "Struct Types" section says that the name of that + // field is "T", which suggests that they are + // identical, but it really means that it's the name + // for the purpose of selector expressions and nothing + // else. We decided that they should be neither + // identical or compatible. + if f.Anonymous { + key += "!" + } + key += f.Name + " " + } + + // XXX(Spec) Do the tags also have to be identical for the + // types to be identical? I certainly hope so, because + // otherwise, this is the only case where two distinct type + // objects can represent identical types. + + t, ok := tMap[key] + if !ok { + // Create new struct type + t = &StructType{commonType{}, fields} + tMap[key] = t + } + return t +} + +func (t *StructType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*StructType) + if !ok { + return false + } + if len(t.Elems) != len(t2.Elems) { + return false + } + for i, e := range t.Elems { + e2 := t2.Elems[i] + // XXX(Spec) An anonymous and a non-anonymous field + // are neither identical nor compatible. + if e.Anonymous != e2.Anonymous || + (!e.Anonymous && e.Name != e2.Name) || + !e.Type.compat(e2.Type, conv) { + return false + } + } + return true +} + +func (t *StructType) lit() Type { return t } + +func (t *StructType) String() string { + s := "struct {" + for i, f := range t.Elems { + if i > 0 { + s += "; " + } + if !f.Anonymous { + s += f.Name + " " + } + s += f.Type.String() + } + return s + "}" +} + +func (t *StructType) Zero() Value { + res := structV(make([]Value, len(t.Elems))) + for i, f := range t.Elems { + res[i] = f.Type.Zero() + } + return &res +} + +/* + * Pointer + */ + +type PtrType struct { + commonType + Elem Type +} + +var ptrTypes = make(map[Type]*PtrType) + +// Two pointer types are identical if they have identical base types. + +func NewPtrType(elem Type) *PtrType { + t, ok := ptrTypes[elem] + if !ok { + t = &PtrType{commonType{}, elem} + ptrTypes[elem] = t + } + return t +} + +func (t *PtrType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*PtrType) + if !ok { + return false + } + return t.Elem.compat(t2.Elem, conv) +} + +func (t *PtrType) lit() Type { return t } + +func (t *PtrType) String() string { return "*" + t.Elem.String() } + +func (t *PtrType) Zero() Value { return &ptrV{nil} } + +/* + * Function + */ + +type FuncType struct { + commonType + // TODO(austin) Separate receiver Type for methods? + In []Type + Variadic bool + Out []Type + builtin string +} + +var funcTypes = newTypeArrayMap() +var variadicFuncTypes = newTypeArrayMap() + +// Create singleton function types for magic built-in functions +var ( + capType = &FuncType{builtin: "cap"} + closeType = &FuncType{builtin: "close"} + closedType = &FuncType{builtin: "closed"} + lenType = &FuncType{builtin: "len"} + makeType = &FuncType{builtin: "make"} + newType = &FuncType{builtin: "new"} + panicType = &FuncType{builtin: "panic"} + printType = &FuncType{builtin: "print"} + printlnType = &FuncType{builtin: "println"} + copyType = &FuncType{builtin: "copy"} +) + +// Two function types are identical if they have the same number of +// parameters and result values and if corresponding parameter and +// result types are identical. All "..." parameters have identical +// type. Parameter and result names are not required to match. + +func NewFuncType(in []Type, variadic bool, out []Type) *FuncType { + inMap := funcTypes + if variadic { + inMap = variadicFuncTypes + } + + outMapI := inMap.Get(in) + if outMapI == nil { + outMapI = inMap.Put(in, newTypeArrayMap()) + } + outMap := outMapI.(typeArrayMap) + + tI := outMap.Get(out) + if tI != nil { + return tI.(*FuncType) + } + + t := &FuncType{commonType{}, in, variadic, out, ""} + outMap.Put(out, t) + return t +} + +func (t *FuncType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*FuncType) + if !ok { + return false + } + if len(t.In) != len(t2.In) || t.Variadic != t2.Variadic || len(t.Out) != len(t2.Out) { + return false + } + for i := range t.In { + if !t.In[i].compat(t2.In[i], conv) { + return false + } + } + for i := range t.Out { + if !t.Out[i].compat(t2.Out[i], conv) { + return false + } + } + return true +} + +func (t *FuncType) lit() Type { return t } + +func typeListString(ts []Type, ns []*ast.Ident) string { + s := "" + for i, t := range ts { + if i > 0 { + s += ", " + } + if ns != nil && ns[i] != nil { + s += ns[i].Name + " " + } + if t == nil { + // Some places use nil types to represent errors + s += "<none>" + } else { + s += t.String() + } + } + return s +} + +func (t *FuncType) String() string { + if t.builtin != "" { + return "built-in function " + t.builtin + } + args := typeListString(t.In, nil) + if t.Variadic { + if len(args) > 0 { + args += ", " + } + args += "..." + } + s := "func(" + args + ")" + if len(t.Out) > 0 { + s += " (" + typeListString(t.Out, nil) + ")" + } + return s +} + +func (t *FuncType) Zero() Value { return &funcV{nil} } + +type FuncDecl struct { + Type *FuncType + Name *ast.Ident // nil for function literals + // InNames will be one longer than Type.In if this function is + // variadic. + InNames []*ast.Ident + OutNames []*ast.Ident +} + +func (t *FuncDecl) String() string { + s := "func" + if t.Name != nil { + s += " " + t.Name.Name + } + s += funcTypeString(t.Type, t.InNames, t.OutNames) + return s +} + +func funcTypeString(ft *FuncType, ins []*ast.Ident, outs []*ast.Ident) string { + s := "(" + s += typeListString(ft.In, ins) + if ft.Variadic { + if len(ft.In) > 0 { + s += ", " + } + s += "..." + } + s += ")" + if len(ft.Out) > 0 { + s += " (" + typeListString(ft.Out, outs) + ")" + } + return s +} + +/* + * Interface + */ + +// TODO(austin) Interface values, types, and type compilation are +// implemented, but none of the type checking or semantics of +// interfaces are. + +type InterfaceType struct { + commonType + // TODO(austin) This should be a map from names to + // *FuncType's. We only need the sorted list for generating + // the type map key. It's detrimental for everything else. + methods []IMethod +} + +type IMethod struct { + Name string + Type *FuncType +} + +var interfaceTypes = newTypeArrayMap() + +func NewInterfaceType(methods []IMethod, embeds []*InterfaceType) *InterfaceType { + // Count methods of embedded interfaces + nMethods := len(methods) + for _, e := range embeds { + nMethods += len(e.methods) + } + + // Combine methods + allMethods := make([]IMethod, nMethods) + copy(allMethods, methods) + n := len(methods) + for _, e := range embeds { + for _, m := range e.methods { + allMethods[n] = m + n++ + } + } + + // Sort methods + sort.Sort(iMethodSorter(allMethods)) + + mts := make([]Type, len(allMethods)) + for i, m := range methods { + mts[i] = m.Type + } + tMapI := interfaceTypes.Get(mts) + if tMapI == nil { + tMapI = interfaceTypes.Put(mts, make(map[string]*InterfaceType)) + } + tMap := tMapI.(map[string]*InterfaceType) + + key := "" + for _, m := range allMethods { + key += m.Name + " " + } + + t, ok := tMap[key] + if !ok { + t = &InterfaceType{commonType{}, allMethods} + tMap[key] = t + } + return t +} + +type iMethodSorter []IMethod + +func (s iMethodSorter) Less(a, b int) bool { return s[a].Name < s[b].Name } + +func (s iMethodSorter) Swap(a, b int) { s[a], s[b] = s[b], s[a] } + +func (s iMethodSorter) Len() int { return len(s) } + +func (t *InterfaceType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*InterfaceType) + if !ok { + return false + } + if len(t.methods) != len(t2.methods) { + return false + } + for i, e := range t.methods { + e2 := t2.methods[i] + if e.Name != e2.Name || !e.Type.compat(e2.Type, conv) { + return false + } + } + return true +} + +func (t *InterfaceType) lit() Type { return t } + +func (t *InterfaceType) String() string { + // TODO(austin) Instead of showing embedded interfaces, this + // shows their methods. + s := "interface {" + for i, m := range t.methods { + if i > 0 { + s += "; " + } + s += m.Name + funcTypeString(m.Type, nil, nil) + } + return s + "}" +} + +// implementedBy tests if o implements t, returning nil, true if it does. +// Otherwise, it returns a method of t that o is missing and false. +func (t *InterfaceType) implementedBy(o Type) (*IMethod, bool) { + if len(t.methods) == 0 { + return nil, true + } + + // The methods of a named interface types are those of the + // underlying type. + if it, ok := o.lit().(*InterfaceType); ok { + o = it + } + + // XXX(Spec) Interface types: "A type implements any interface + // comprising any subset of its methods" It's unclear if + // methods must have identical or compatible types. 6g + // requires identical types. + + switch o := o.(type) { + case *NamedType: + for _, tm := range t.methods { + sm, ok := o.methods[tm.Name] + if !ok || sm.decl.Type != tm.Type { + return &tm, false + } + } + return nil, true + + case *InterfaceType: + var ti, oi int + for ti < len(t.methods) && oi < len(o.methods) { + tm, om := &t.methods[ti], &o.methods[oi] + switch { + case tm.Name == om.Name: + if tm.Type != om.Type { + return tm, false + } + ti++ + oi++ + case tm.Name > om.Name: + oi++ + default: + return tm, false + } + } + if ti < len(t.methods) { + return &t.methods[ti], false + } + return nil, true + } + + return &t.methods[0], false +} + +func (t *InterfaceType) Zero() Value { return &interfaceV{} } + +/* + * Slice + */ + +type SliceType struct { + commonType + Elem Type +} + +var sliceTypes = make(map[Type]*SliceType) + +// Two slice types are identical if they have identical element types. + +func NewSliceType(elem Type) *SliceType { + t, ok := sliceTypes[elem] + if !ok { + t = &SliceType{commonType{}, elem} + sliceTypes[elem] = t + } + return t +} + +func (t *SliceType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*SliceType) + if !ok { + return false + } + return t.Elem.compat(t2.Elem, conv) +} + +func (t *SliceType) lit() Type { return t } + +func (t *SliceType) String() string { return "[]" + t.Elem.String() } + +func (t *SliceType) Zero() Value { + // The value of an uninitialized slice is nil. The length and + // capacity of a nil slice are 0. + return &sliceV{Slice{nil, 0, 0}} +} + +/* + * Map type + */ + +type MapType struct { + commonType + Key Type + Elem Type +} + +var mapTypes = make(map[Type]map[Type]*MapType) + +func NewMapType(key Type, elem Type) *MapType { + ts, ok := mapTypes[key] + if !ok { + ts = make(map[Type]*MapType) + mapTypes[key] = ts + } + t, ok := ts[elem] + if !ok { + t = &MapType{commonType{}, key, elem} + ts[elem] = t + } + return t +} + +func (t *MapType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*MapType) + if !ok { + return false + } + return t.Elem.compat(t2.Elem, conv) && t.Key.compat(t2.Key, conv) +} + +func (t *MapType) lit() Type { return t } + +func (t *MapType) String() string { return "map[" + t.Key.String() + "] " + t.Elem.String() } + +func (t *MapType) Zero() Value { + // The value of an uninitialized map is nil. + return &mapV{nil} +} + +/* +type ChanType struct { + // TODO(austin) +} +*/ + +/* + * Named types + */ + +type Method struct { + decl *FuncDecl + fn Func +} + +type NamedType struct { + NamePos token.Pos + Name string + // Underlying type. If incomplete is true, this will be nil. + // If incomplete is false and this is still nil, then this is + // a placeholder type representing an error. + Def Type + // True while this type is being defined. + incomplete bool + methods map[string]Method +} + +// TODO(austin) This is temporarily needed by the debugger's remote +// type parser. This should only be possible with block.DefineType. +func NewNamedType(name string) *NamedType { + return &NamedType{token.NoPos, name, nil, true, make(map[string]Method)} +} + +func (t *NamedType) Pos() token.Pos { + return t.NamePos +} + +func (t *NamedType) Complete(def Type) { + if !t.incomplete { + log.Panicf("cannot complete already completed NamedType %+v", *t) + } + // We strip the name from def because multiple levels of + // naming are useless. + if ndef, ok := def.(*NamedType); ok { + def = ndef.Def + } + t.Def = def + t.incomplete = false +} + +func (t *NamedType) compat(o Type, conv bool) bool { + t2, ok := o.(*NamedType) + if ok { + if conv { + // Two named types are conversion compatible + // if their literals are conversion + // compatible. + return t.Def.compat(t2.Def, conv) + } else { + // Two named types are compatible if their + // type names originate in the same type + // declaration. + return t == t2 + } + } + // A named and an unnamed type are compatible if the + // respective type literals are compatible. + return o.compat(t.Def, conv) +} + +func (t *NamedType) lit() Type { return t.Def.lit() } + +func (t *NamedType) isBoolean() bool { return t.Def.isBoolean() } + +func (t *NamedType) isInteger() bool { return t.Def.isInteger() } + +func (t *NamedType) isFloat() bool { return t.Def.isFloat() } + +func (t *NamedType) isIdeal() bool { return false } + +func (t *NamedType) String() string { return t.Name } + +func (t *NamedType) Zero() Value { return t.Def.Zero() } + +/* + * Multi-valued type + */ + +// MultiType is a special type used for multi-valued expressions, akin +// to a tuple type. It's not generally accessible within the +// language. +type MultiType struct { + commonType + Elems []Type +} + +var multiTypes = newTypeArrayMap() + +func NewMultiType(elems []Type) *MultiType { + if t := multiTypes.Get(elems); t != nil { + return t.(*MultiType) + } + + t := &MultiType{commonType{}, elems} + multiTypes.Put(elems, t) + return t +} + +func (t *MultiType) compat(o Type, conv bool) bool { + t2, ok := o.lit().(*MultiType) + if !ok { + return false + } + if len(t.Elems) != len(t2.Elems) { + return false + } + for i := range t.Elems { + if !t.Elems[i].compat(t2.Elems[i], conv) { + return false + } + } + return true +} + +var EmptyType Type = NewMultiType([]Type{}) + +func (t *MultiType) lit() Type { return t } + +func (t *MultiType) String() string { + if len(t.Elems) == 0 { + return "<none>" + } + return typeListString(t.Elems, nil) +} + +func (t *MultiType) Zero() Value { + res := make([]Value, len(t.Elems)) + for i, t := range t.Elems { + res[i] = t.Zero() + } + return multiV(res) +} + +/* + * Initialize the universe + */ + +func init() { + numer := big.NewInt(0xffffff) + numer.Lsh(numer, 127-23) + maxFloat32Val = new(big.Rat).SetInt(numer) + numer.SetInt64(0x1fffffffffffff) + numer.Lsh(numer, 1023-52) + maxFloat64Val = new(big.Rat).SetInt(numer) + minFloat32Val = new(big.Rat).Neg(maxFloat32Val) + minFloat64Val = new(big.Rat).Neg(maxFloat64Val) + + // To avoid portability issues all numeric types are distinct + // except byte, which is an alias for uint8. + + // Make byte an alias for the named type uint8. Type aliases + // are otherwise impossible in Go, so just hack it here. + universe.defs["byte"] = universe.defs["uint8"] + + // Built-in functions + universe.DefineConst("cap", universePos, capType, nil) + universe.DefineConst("close", universePos, closeType, nil) + universe.DefineConst("closed", universePos, closedType, nil) + universe.DefineConst("copy", universePos, copyType, nil) + universe.DefineConst("len", universePos, lenType, nil) + universe.DefineConst("make", universePos, makeType, nil) + universe.DefineConst("new", universePos, newType, nil) + universe.DefineConst("panic", universePos, panicType, nil) + universe.DefineConst("print", universePos, printType, nil) + universe.DefineConst("println", universePos, printlnType, nil) +} |