blob: 47e2285238da6235915866488283b2bcedaa5166 [file] [log] [blame]
// 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 (
"bignum";
"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.Position;
}
type BoundedType interface {
Type;
// minVal returns the smallest value of this type.
minVal() *bignum.Rational;
// maxVal returns the largest value of this type.
maxVal() *bignum.Rational;
}
var universePos = token.Position{"<universe>", 0, 0, 0}
/*
* 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.Position { return token.Position{} }
/*
* 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: ", t.Bits);
}
func (t *uintType) minVal() *bignum.Rational { return bignum.Rat(0, 1) }
func (t *uintType) maxVal() *bignum.Rational {
bits := t.Bits;
if bits == 0 {
if t.Ptr {
bits = uint(8 * unsafe.Sizeof(uintptr(0)))
} else {
bits = uint(8 * unsafe.Sizeof(uint(0)))
}
}
return bignum.MakeRat(bignum.Int(1).Shl(bits).Add(bignum.Int(-1)), bignum.Nat(1));
}
/*
* 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: ", t.Bits);
}
func (t *intType) minVal() *bignum.Rational {
bits := t.Bits;
if bits == 0 {
bits = uint(8 * unsafe.Sizeof(int(0)))
}
return bignum.MakeRat(bignum.Int(-1).Shl(bits-1), bignum.Nat(1));
}
func (t *intType) maxVal() *bignum.Rational {
bits := t.Bits;
if bits == 0 {
bits = uint(8 * unsafe.Sizeof(int(0)))
}
return bignum.MakeRat(bignum.Int(1).Shl(bits-1).Add(bignum.Int(-1)), bignum.Nat(1));
}
/*
* 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{bignum.Int(0)} }
/*
* 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"});
FloatType = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"});
)
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;
case 0:
res := floatV(0);
return &res;
}
panic("unexpected float bit count: ", t.Bits);
}
var maxFloat32Val = bignum.MakeRat(bignum.Int(0xffffff).Shl(127-23), bignum.Nat(1))
var maxFloat64Val = bignum.MakeRat(bignum.Int(0x1fffffffffffff).Shl(1023-52), bignum.Nat(1))
var minFloat32Val = maxFloat32Val.Neg()
var minFloat64Val = maxFloat64Val.Neg()
func (t *floatType) minVal() *bignum.Rational {
bits := t.Bits;
if bits == 0 {
bits = uint(8 * unsafe.Sizeof(float(0)))
}
switch bits {
case 32:
return minFloat32Val
case 64:
return minFloat64Val
}
log.Crashf("unexpected floating point bit count: %d", bits);
panic();
}
func (t *floatType) maxVal() *bignum.Rational {
bits := t.Bits;
if bits == 0 {
bits = uint(8 * unsafe.Sizeof(float(0)))
}
switch bits {
case 32:
return maxFloat32Val
case 64:
return maxFloat64Val
}
log.Crashf("unexpected floating point bit count: %d", bits);
panic();
}
/*
* 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{bignum.Rat(1, 0)} }
/*
* 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"};
paniclnType = &FuncType{builtin: "panicln"};
printType = &FuncType{builtin: "print"};
printlnType = &FuncType{builtin: "println"};
)
// 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].Value + " "
}
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.Value
}
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);
for i, m := range methods {
allMethods[i] = m
}
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 {
token.Position;
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.Position{}, name, nil, true, make(map[string]Method)}
}
func (t *NamedType) Complete(def Type) {
if !t.incomplete {
log.Crashf("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() {
// 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("len", universePos, lenType, nil);
universe.DefineConst("make", universePos, makeType, nil);
universe.DefineConst("new", universePos, newType, nil);
universe.DefineConst("panic", universePos, panicType, nil);
universe.DefineConst("panicln", universePos, paniclnType, nil);
universe.DefineConst("print", universePos, printType, nil);
universe.DefineConst("println", universePos, printlnType, nil);
}