mirror of
https://github.com/golang/go
synced 2024-11-12 04:40:22 -07:00
Implement struct types, selector expressions, and type
declarations. R=rsc APPROVED=rsc DELTA=587 (519 added, 21 deleted, 47 changed) OCL=32754 CL=32788
This commit is contained in:
parent
6b7bf38487
commit
6adadeb3ab
@ -39,6 +39,7 @@ type assignCompiler struct
|
||||
func (a *compiler) checkAssign(pos token.Position, rs []*exprCompiler, errOp, errPosName string) (*assignCompiler, bool)
|
||||
func (a *compiler) compileAssign(pos token.Position, lt Type, rs []*exprCompiler, errOp, errPosName string) (func(lv Value, f *Frame))
|
||||
func (a *compiler) compileType(b *block, typ ast.Expr) Type
|
||||
func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool
|
||||
func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl
|
||||
|
||||
func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool)
|
||||
|
@ -22,6 +22,8 @@ type Type interface {
|
||||
// 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
|
||||
@ -113,6 +115,13 @@ type ArrayValue interface {
|
||||
Elem(i int64) Value;
|
||||
}
|
||||
|
||||
type StructValue interface {
|
||||
Value;
|
||||
// TODO(austin) This is another useless Get()
|
||||
Get() StructValue;
|
||||
Field(i int) Value;
|
||||
}
|
||||
|
||||
type PtrValue interface {
|
||||
Value;
|
||||
Get() Value;
|
||||
|
@ -35,6 +35,7 @@ type exprCompiler struct {
|
||||
evalIdealFloat func() *bignum.Rational;
|
||||
evalString func(f *Frame) string;
|
||||
evalArray func(f *Frame) ArrayValue;
|
||||
evalStruct func(f *Frame) StructValue;
|
||||
evalPtr func(f *Frame) Value;
|
||||
evalFunc func(f *Frame) Func;
|
||||
evalMulti func(f *Frame) []Value;
|
||||
@ -64,7 +65,7 @@ func (a *exprCompiler) genConstant(v Value)
|
||||
func (a *exprCompiler) genIdentOp(level int, index int)
|
||||
func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler)
|
||||
func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value)
|
||||
func (a *exprCompiler) genStarOp(v *exprCompiler)
|
||||
func (a *exprCompiler) genValue(vf func(*Frame) Value)
|
||||
func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler)
|
||||
func (a *exprCompiler) genUnaryOpNot(v *exprCompiler)
|
||||
func (a *exprCompiler) genUnaryOpXor(v *exprCompiler)
|
||||
@ -172,6 +173,13 @@ func (a *exprCompiler) asArray() (func(f *Frame) ArrayValue) {
|
||||
return a.evalArray;
|
||||
}
|
||||
|
||||
func (a *exprCompiler) asStruct() (func(f *Frame) StructValue) {
|
||||
if a.evalStruct == nil {
|
||||
log.Crashf("tried to get %v node as StructType", a.t);
|
||||
}
|
||||
return a.evalStruct;
|
||||
}
|
||||
|
||||
func (a *exprCompiler) asPtr() (func(f *Frame) Value) {
|
||||
if a.evalPtr == nil {
|
||||
log.Crashf("tried to get %v node as PtrType", a.t);
|
||||
@ -272,6 +280,10 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler {
|
||||
return res;
|
||||
}
|
||||
|
||||
func (a *exprCompiler) genStarOp(v *exprCompiler) {
|
||||
a.genValue(v.asPtr());
|
||||
}
|
||||
|
||||
/*
|
||||
* Assignments
|
||||
*/
|
||||
@ -596,7 +608,135 @@ func (a *exprCompiler) DoParenExpr(x *ast.ParenExpr) {
|
||||
}
|
||||
|
||||
func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) {
|
||||
log.Crash("Not implemented");
|
||||
v := a.copyVisit(x.X);
|
||||
if v.t == nil {
|
||||
return;
|
||||
}
|
||||
|
||||
// mark marks a field that matches the selector name. It
|
||||
// tracks the best depth found so far and whether more than
|
||||
// one field has been found at that depth.
|
||||
bestDepth := -1;
|
||||
ambig := false;
|
||||
amberr := "";
|
||||
mark := func(depth int, pathName string) {
|
||||
switch {
|
||||
case bestDepth == -1 || depth < bestDepth:
|
||||
bestDepth = depth;
|
||||
ambig = false;
|
||||
amberr = "";
|
||||
|
||||
case depth == bestDepth:
|
||||
ambig = true;
|
||||
|
||||
default:
|
||||
log.Crashf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth);
|
||||
}
|
||||
amberr += "\n\t" + pathName[1:len(pathName)];
|
||||
};
|
||||
|
||||
name := x.Sel.Value;
|
||||
visited := make(map[Type] bool);
|
||||
|
||||
// find recursively searches for the named field, starting at
|
||||
// type t. If it finds the named field, it returns a function
|
||||
// which takes an exprCompiler that retrieves a value of type
|
||||
// 't' and fills 'a' to retrieve the named field. We delay
|
||||
// exprCompiler construction to avoid filling in anything
|
||||
// until we're sure we have the right field, and to avoid
|
||||
// producing lots of garbage exprCompilers as we search.
|
||||
var find func(Type, int, string) (func (*exprCompiler));
|
||||
find = func(t Type, depth int, pathName string) (func (*exprCompiler)) {
|
||||
// Don't bother looking if we've found something shallower
|
||||
if bestDepth != -1 && bestDepth < depth {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Don't check the same type twice and avoid loops
|
||||
if _, ok := visited[t]; ok {
|
||||
return nil;
|
||||
}
|
||||
visited[t] = true;
|
||||
|
||||
// Implicit dereference
|
||||
deref := false;
|
||||
if ti, ok := t.(*PtrType); ok {
|
||||
deref = true;
|
||||
t = ti.Elem;
|
||||
}
|
||||
|
||||
// If it's a named type, look for methods
|
||||
if ti, ok := t.(*NamedType); ok {
|
||||
method, ok := ti.methods[name];
|
||||
if ok {
|
||||
mark(depth, pathName + "." + name);
|
||||
log.Crash("Methods not implemented");
|
||||
}
|
||||
t = ti.def;
|
||||
}
|
||||
|
||||
// If it's a struct type, check fields and embedded types
|
||||
var builder func(*exprCompiler);
|
||||
if t, ok := t.(*StructType); ok {
|
||||
for i, f := range t.Elems {
|
||||
var this *exprCompiler;
|
||||
var sub func(*exprCompiler);
|
||||
switch {
|
||||
case f.Name == name:
|
||||
mark(depth, pathName + "." + name);
|
||||
this = a;
|
||||
sub = func(*exprCompiler) {};
|
||||
|
||||
case f.Anonymous:
|
||||
sub = find(f.Type, depth+1, pathName + "." + f.Name);
|
||||
if sub == nil {
|
||||
continue;
|
||||
}
|
||||
this = a.copy();
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
// We found something. Create a
|
||||
// builder for accessing this field.
|
||||
ft := f.Type;
|
||||
index := i;
|
||||
builder = func(parent *exprCompiler) {
|
||||
this.t = ft;
|
||||
var evalAddr func(f *Frame) Value;
|
||||
if deref {
|
||||
pf := parent.asPtr();
|
||||
evalAddr = func(f *Frame) Value {
|
||||
return pf(f).(StructValue).Field(index);
|
||||
};
|
||||
} else {
|
||||
pf := parent.asStruct();
|
||||
evalAddr = func(f *Frame) Value {
|
||||
return pf(f).Field(index);
|
||||
};
|
||||
}
|
||||
this.genValue(evalAddr);
|
||||
sub(this);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
};
|
||||
|
||||
builder := find(v.t, 0, "");
|
||||
if builder == nil {
|
||||
a.diag("type %v has no field or method %s", v.t, name);
|
||||
return;
|
||||
}
|
||||
if ambig {
|
||||
a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr);
|
||||
return;
|
||||
}
|
||||
|
||||
a.desc = "selector expression";
|
||||
builder(v);
|
||||
}
|
||||
|
||||
func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) {
|
||||
@ -810,6 +950,7 @@ func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) {
|
||||
switch vt := v.t.lit().(type) {
|
||||
case *PtrType:
|
||||
a.t = vt.Elem;
|
||||
// TODO(austin) Deal with nil pointers
|
||||
a.genStarOp(v);
|
||||
a.desc = "indirect expression";
|
||||
|
||||
@ -1134,10 +1275,15 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) {
|
||||
return;
|
||||
}
|
||||
// Arrays and structs may not be compared to anything.
|
||||
// TODO(austin) Use a multi-type switch
|
||||
if _, ok := l.t.(*ArrayType); ok {
|
||||
a.diagOpTypes(op, origlt, origrt);
|
||||
return;
|
||||
}
|
||||
if _, ok := l.t.(*StructType); ok {
|
||||
a.diagOpTypes(op, origlt, origrt);
|
||||
return;
|
||||
}
|
||||
a.t = BoolType;
|
||||
|
||||
default:
|
||||
@ -1283,11 +1429,8 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
|
||||
if lenExpr == nil {
|
||||
return 0, false;
|
||||
}
|
||||
if !lenExpr.t.isInteger() {
|
||||
a.diagAt(expr, "array size must be an integer");
|
||||
return 0, false;
|
||||
}
|
||||
|
||||
// XXX(Spec) Are ideal floats with no fractional part okay?
|
||||
if lenExpr.t.isIdeal() {
|
||||
lenExpr = lenExpr.convertTo(IntType);
|
||||
if lenExpr == nil {
|
||||
@ -1295,6 +1438,11 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if !lenExpr.t.isInteger() {
|
||||
a.diagAt(expr, "array size must be an integer");
|
||||
return 0, false;
|
||||
}
|
||||
|
||||
switch _ := lenExpr.t.lit().(type) {
|
||||
case *intType:
|
||||
return lenExpr.evalInt(nil), true;
|
||||
@ -1442,6 +1590,9 @@ func (a *exprCompiler) genConstant(v Value) {
|
||||
case *ArrayType:
|
||||
val := v.(ArrayValue).Get();
|
||||
a.evalArray = func(f *Frame) ArrayValue { return val };
|
||||
case *StructType:
|
||||
val := v.(StructValue).Get();
|
||||
a.evalStruct = func(f *Frame) StructValue { return val };
|
||||
case *PtrType:
|
||||
val := v.(PtrValue).Get();
|
||||
a.evalPtr = func(f *Frame) Value { return val };
|
||||
@ -1468,6 +1619,8 @@ func (a *exprCompiler) genIdentOp(level int, index int) {
|
||||
a.evalString = func(f *Frame) string { return f.Get(level, index).(StringValue).Get() };
|
||||
case *ArrayType:
|
||||
a.evalArray = func(f *Frame) ArrayValue { return f.Get(level, index).(ArrayValue).Get() };
|
||||
case *StructType:
|
||||
a.evalStruct = func(f *Frame) StructValue { return f.Get(level, index).(StructValue).Get() };
|
||||
case *PtrType:
|
||||
a.evalPtr = func(f *Frame) Value { return f.Get(level, index).(PtrValue).Get() };
|
||||
case *FuncType:
|
||||
@ -1493,6 +1646,8 @@ func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler) {
|
||||
a.evalString = func(f *Frame) string { return lf(f).Elem(rf(f)).(StringValue).Get() };
|
||||
case *ArrayType:
|
||||
a.evalArray = func(f *Frame) ArrayValue { return lf(f).Elem(rf(f)).(ArrayValue).Get() };
|
||||
case *StructType:
|
||||
a.evalStruct = func(f *Frame) StructValue { return lf(f).Elem(rf(f)).(StructValue).Get() };
|
||||
case *PtrType:
|
||||
a.evalPtr = func(f *Frame) Value { return lf(f).Elem(rf(f)).(PtrValue).Get() };
|
||||
case *FuncType:
|
||||
@ -1517,6 +1672,8 @@ func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) {
|
||||
a.evalString = func(f *Frame) string { return call(f)[0].(StringValue).Get() };
|
||||
case *ArrayType:
|
||||
a.evalArray = func(f *Frame) ArrayValue { return call(f)[0].(ArrayValue).Get() };
|
||||
case *StructType:
|
||||
a.evalStruct = func(f *Frame) StructValue { return call(f)[0].(StructValue).Get() };
|
||||
case *PtrType:
|
||||
a.evalPtr = func(f *Frame) Value { return call(f)[0].(PtrValue).Get() };
|
||||
case *FuncType:
|
||||
@ -1528,9 +1685,8 @@ func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *exprCompiler) genStarOp(v *exprCompiler) {
|
||||
vf := v.asPtr();
|
||||
a.evalAddr = func(f *Frame) Value { return vf(f) };
|
||||
func (a *exprCompiler) genValue(vf func(*Frame) Value) {
|
||||
a.evalAddr = vf;
|
||||
switch _ := a.t.lit().(type) {
|
||||
case *boolType:
|
||||
a.evalBool = func(f *Frame) bool { return vf(f).(BoolValue).Get() };
|
||||
@ -1544,6 +1700,8 @@ func (a *exprCompiler) genStarOp(v *exprCompiler) {
|
||||
a.evalString = func(f *Frame) string { return vf(f).(StringValue).Get() };
|
||||
case *ArrayType:
|
||||
a.evalArray = func(f *Frame) ArrayValue { return vf(f).(ArrayValue).Get() };
|
||||
case *StructType:
|
||||
a.evalStruct = func(f *Frame) StructValue { return vf(f).(StructValue).Get() };
|
||||
case *PtrType:
|
||||
a.evalPtr = func(f *Frame) Value { return vf(f).(PtrValue).Get() };
|
||||
case *FuncType:
|
||||
|
@ -86,7 +86,10 @@ func (b *block) DefineType(name string, pos token.Position, t Type) Type {
|
||||
}
|
||||
// We take the representative type of t because multiple
|
||||
// levels of naming are useless.
|
||||
nt := &NamedType{pos, name, t.lit()};
|
||||
if t != nil {
|
||||
t = t.lit();
|
||||
}
|
||||
nt := &NamedType{pos, name, t, false, make(map[string] Method)};
|
||||
b.defs[name] = nt;
|
||||
return nt;
|
||||
}
|
||||
|
@ -256,10 +256,12 @@ func (a *stmtCompiler) DoBadStmt(s *ast.BadStmt) {
|
||||
}
|
||||
|
||||
func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) {
|
||||
ok := true;
|
||||
|
||||
switch decl := s.Decl.(type) {
|
||||
case *ast.BadDecl:
|
||||
// Do nothing. Already reported by parser.
|
||||
return;
|
||||
ok = false;
|
||||
|
||||
case *ast.FuncDecl:
|
||||
log.Crash("FuncDecl at statement level");
|
||||
@ -269,21 +271,22 @@ func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) {
|
||||
case token.IMPORT:
|
||||
log.Crash("import at statement level");
|
||||
|
||||
case token.CONST, token.TYPE:
|
||||
case token.CONST:
|
||||
log.Crashf("%v not implemented", decl.Tok);
|
||||
|
||||
case token.TYPE:
|
||||
ok = a.compileTypeDecl(a.block, decl);
|
||||
|
||||
case token.VAR:
|
||||
ok := true;
|
||||
for _, spec := range decl.Specs {
|
||||
spec := spec.(*ast.ValueSpec);
|
||||
if spec.Values == nil {
|
||||
// Declaration without assignment
|
||||
var t Type;
|
||||
if spec.Type == nil {
|
||||
// Parser should have caught
|
||||
log.Crash("Type and Values nil");
|
||||
}
|
||||
t = a.compileType(a.block, spec.Type);
|
||||
t := a.compileType(a.block, spec.Type);
|
||||
if t == nil {
|
||||
// Define placeholders
|
||||
ok = false;
|
||||
@ -300,15 +303,21 @@ func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) {
|
||||
lhs[i] = n;
|
||||
}
|
||||
a.doAssign(lhs, spec.Values, decl.Tok, spec.Type);
|
||||
// TODO(austin) This is rediculous. doAssign
|
||||
// indicates failure by setting a.err.
|
||||
if a.err {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
a.err = false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Crashf("Unexpected Decl type %T", s.Decl);
|
||||
}
|
||||
|
||||
if ok {
|
||||
a.err = false;
|
||||
}
|
||||
}
|
||||
|
||||
func (a *stmtCompiler) DoEmptyStmt(s *ast.EmptyStmt) {
|
||||
|
@ -489,6 +489,125 @@ func (t *ArrayType) String() string {
|
||||
|
||||
func (t *ArrayType) Zero() Value
|
||||
|
||||
/*
|
||||
* Struct
|
||||
*/
|
||||
|
||||
type StructField struct {
|
||||
Name string;
|
||||
Type Type;
|
||||
Anonymous bool;
|
||||
}
|
||||
|
||||
type StructType struct {
|
||||
commonType;
|
||||
Elems []StructField;
|
||||
maxDepth int;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// Compute max anonymous field depth
|
||||
maxDepth := 1;
|
||||
for _, f := range fields {
|
||||
// TODO(austin) Careful of type T struct { *T }
|
||||
if st, ok := f.Type.(*StructType); ok {
|
||||
if st.maxDepth + 1 > maxDepth {
|
||||
maxDepth = st.maxDepth + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t = &StructType{commonType{}, fields, maxDepth};
|
||||
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
|
||||
|
||||
/*
|
||||
* Pointer
|
||||
*/
|
||||
@ -682,13 +801,21 @@ type ChanType struct {
|
||||
* Named types
|
||||
*/
|
||||
|
||||
type Method struct {
|
||||
decl *FuncDecl;
|
||||
fn Func;
|
||||
}
|
||||
|
||||
type NamedType struct {
|
||||
token.Position;
|
||||
name string;
|
||||
// Underlying type
|
||||
// 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;
|
||||
// TODO(austin) Methods can be on NamedType or *NamedType
|
||||
//methods map[string] XXX;
|
||||
// True while this type is being defined.
|
||||
incomplete bool;
|
||||
methods map[string] Method;
|
||||
}
|
||||
|
||||
func (t *NamedType) compat(o Type, conv bool) bool {
|
||||
|
@ -7,6 +7,7 @@ package eval
|
||||
import (
|
||||
"eval";
|
||||
"go/ast";
|
||||
"go/token";
|
||||
"log";
|
||||
)
|
||||
|
||||
@ -24,11 +25,16 @@ type exprCompiler struct
|
||||
type typeCompiler struct {
|
||||
*compiler;
|
||||
block *block;
|
||||
// Check to be performed after a type declaration is compiled.
|
||||
//
|
||||
// TODO(austin) This will probably have to change after we
|
||||
// eliminate forward declarations.
|
||||
lateCheck func() bool
|
||||
}
|
||||
|
||||
func (a *typeCompiler) compileType(x ast.Expr) Type
|
||||
func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type
|
||||
|
||||
func (a *typeCompiler) compileIdent(x *ast.Ident) Type {
|
||||
func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
|
||||
_, def := a.block.Lookup(x.Value);
|
||||
if def == nil {
|
||||
a.diagAt(x, "%s: undefined", x.Value);
|
||||
@ -41,6 +47,16 @@ func (a *typeCompiler) compileIdent(x *ast.Ident) Type {
|
||||
case *Variable:
|
||||
a.diagAt(x, "variable %v used as type", x.Value);
|
||||
return nil;
|
||||
case *NamedType:
|
||||
if !allowRec && def.incomplete {
|
||||
a.diagAt(x, "illegal recursive type");
|
||||
return nil;
|
||||
}
|
||||
if !def.incomplete && def.def == nil {
|
||||
// Placeholder type from an earlier error
|
||||
return nil;
|
||||
}
|
||||
return def;
|
||||
case Type:
|
||||
return def;
|
||||
}
|
||||
@ -48,7 +64,7 @@ func (a *typeCompiler) compileIdent(x *ast.Ident) Type {
|
||||
return nil;
|
||||
}
|
||||
|
||||
func (a *typeCompiler) compileArrayType(x *ast.ArrayType) *ArrayType {
|
||||
func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
|
||||
// Compile length expression
|
||||
if x.Len == nil {
|
||||
a.diagAt(x, "slice types not implemented");
|
||||
@ -61,7 +77,7 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType) *ArrayType {
|
||||
l, ok := a.compileArrayLen(a.block, x.Len);
|
||||
|
||||
// Compile element type
|
||||
elem := a.compileType(x.Elt);
|
||||
elem := a.compileType(x.Elt, allowRec);
|
||||
|
||||
if !ok {
|
||||
return nil;
|
||||
@ -77,14 +93,6 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType) *ArrayType {
|
||||
return NewArrayType(l, elem);
|
||||
}
|
||||
|
||||
func (a *typeCompiler) compilePtrType(x *ast.StarExpr) *PtrType {
|
||||
elem := a.compileType(x.X);
|
||||
if elem == nil {
|
||||
return nil;
|
||||
}
|
||||
return NewPtrType(elem);
|
||||
}
|
||||
|
||||
func countFields(fs []*ast.Field) int {
|
||||
n := 0;
|
||||
for _, f := range fs {
|
||||
@ -97,71 +105,164 @@ func countFields(fs []*ast.Field) int {
|
||||
return n;
|
||||
}
|
||||
|
||||
func (a *typeCompiler) compileFields(fs []*ast.Field) ([]Type, []*ast.Ident) {
|
||||
func (a *typeCompiler) compileFields(fs []*ast.Field, allowRec bool) ([]Type, []*ast.Ident, []token.Position, bool) {
|
||||
n := countFields(fs);
|
||||
ts := make([]Type, n);
|
||||
ns := make([]*ast.Ident, n);
|
||||
ps := make([]token.Position, n);
|
||||
|
||||
bad := false;
|
||||
i := 0;
|
||||
for fi, f := range fs {
|
||||
t := a.compileType(f.Type);
|
||||
t := a.compileType(f.Type, allowRec);
|
||||
if t == nil {
|
||||
bad = true;
|
||||
}
|
||||
if f.Names == nil {
|
||||
// TODO(austin) In a struct, this has an
|
||||
// implicit name. However, this also triggers
|
||||
// for function return values, which should
|
||||
// not be given names.
|
||||
ns[i] = nil;
|
||||
ts[i] = t;
|
||||
ps[i] = f.Type.Pos();
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
for _, n := range f.Names {
|
||||
ns[i] = n;
|
||||
ts[i] = t;
|
||||
ps[i] = n.Pos();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if bad {
|
||||
return nil, nil;
|
||||
}
|
||||
return ts, ns;
|
||||
return ts, ns, ps, bad;
|
||||
}
|
||||
|
||||
func (a *typeCompiler) compileFuncType(x *ast.FuncType) *FuncDecl {
|
||||
func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type {
|
||||
ts, names, poss, bad := a.compileFields(x.Fields, allowRec);
|
||||
|
||||
// XXX(Spec) The spec claims that field identifiers must be
|
||||
// unique, but 6g only checks this when they are accessed. I
|
||||
// think the spec is better in this regard: if I write two
|
||||
// fields with the same name in the same struct type, clearly
|
||||
// that's a mistake. This definition does *not* descend into
|
||||
// anonymous fields, so it doesn't matter if those change.
|
||||
// There's separate language in the spec about checking
|
||||
// uniqueness of field names inherited from anonymous fields
|
||||
// at use time.
|
||||
fields := make([]StructField, len(ts));
|
||||
nameSet := make(map[string] token.Position, len(ts));
|
||||
for i := range fields {
|
||||
// Compute field name and check anonymous fields
|
||||
var name string;
|
||||
if names[i] != nil {
|
||||
name = names[i].Value;
|
||||
} else {
|
||||
if ts[i] == nil {
|
||||
continue;
|
||||
}
|
||||
|
||||
var nt *NamedType;
|
||||
// [For anonymous fields,] the unqualified
|
||||
// type name acts as the field identifier.
|
||||
switch t := ts[i].(type) {
|
||||
case *NamedType:
|
||||
name = t.name;
|
||||
nt = t;
|
||||
case *PtrType:
|
||||
switch t := t.Elem.(type) {
|
||||
case *NamedType:
|
||||
name = t.name;
|
||||
nt = t;
|
||||
}
|
||||
}
|
||||
// [An anonymous field] must be specified as a
|
||||
// type name T or as a pointer to a type name
|
||||
// *T, and T itself, may not be a pointer or
|
||||
// interface type.
|
||||
if nt == nil {
|
||||
a.diagAt(&poss[i], "embedded type must T or *T, where T is a named type");
|
||||
bad = true;
|
||||
continue;
|
||||
}
|
||||
// The check for embedded pointer types must
|
||||
// be deferred because of things like
|
||||
// type T *struct { T }
|
||||
lateCheck := a.lateCheck;
|
||||
a.lateCheck = func() bool {
|
||||
if _, ok := nt.lit().(*PtrType); ok {
|
||||
a.diagAt(&poss[i], "embedded type %v is a pointer type", nt);
|
||||
return false;
|
||||
}
|
||||
return lateCheck();
|
||||
};
|
||||
}
|
||||
|
||||
// Check name uniqueness
|
||||
if prev, ok := nameSet[name]; ok {
|
||||
a.diagAt(&poss[i], "field %s redeclared\n\tprevious declaration at %s", name, &prev);
|
||||
bad = true;
|
||||
continue;
|
||||
}
|
||||
nameSet[name] = poss[i];
|
||||
|
||||
// Create field
|
||||
fields[i].Name = name;
|
||||
fields[i].Type = ts[i];
|
||||
fields[i].Anonymous = (names[i] == nil);
|
||||
}
|
||||
|
||||
if bad {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return NewStructType(fields);
|
||||
}
|
||||
|
||||
func (a *typeCompiler) compilePtrType(x *ast.StarExpr) Type {
|
||||
elem := a.compileType(x.X, true);
|
||||
if elem == nil {
|
||||
return nil;
|
||||
}
|
||||
return NewPtrType(elem);
|
||||
}
|
||||
|
||||
func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl {
|
||||
// TODO(austin) Variadic function types
|
||||
|
||||
bad := false;
|
||||
// The types of parameters and results must be complete.
|
||||
//
|
||||
// TODO(austin) It's not clear they actually have to be complete.
|
||||
in, inNames, _, inBad := a.compileFields(x.Params, allowRec);
|
||||
out, outNames, _, outBad := a.compileFields(x.Results, allowRec);
|
||||
|
||||
in, inNames := a.compileFields(x.Params);
|
||||
out, outNames := a.compileFields(x.Results);
|
||||
|
||||
if in == nil || out == nil {
|
||||
if inBad || outBad {
|
||||
return nil;
|
||||
}
|
||||
return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames};
|
||||
}
|
||||
|
||||
func (a *typeCompiler) compileType(x ast.Expr) Type {
|
||||
func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
|
||||
switch x := x.(type) {
|
||||
case *ast.BadExpr:
|
||||
return nil;
|
||||
|
||||
case *ast.Ident:
|
||||
return a.compileIdent(x);
|
||||
return a.compileIdent(x, allowRec);
|
||||
|
||||
case *ast.ArrayType:
|
||||
return a.compileArrayType(x);
|
||||
return a.compileArrayType(x, allowRec);
|
||||
|
||||
case *ast.StructType:
|
||||
goto notimpl;
|
||||
return a.compileStructType(x, allowRec);
|
||||
|
||||
case *ast.StarExpr:
|
||||
return a.compilePtrType(x);
|
||||
|
||||
case *ast.FuncType:
|
||||
return a.compileFuncType(x).Type;
|
||||
fd := a.compileFuncType(x, allowRec);
|
||||
if fd == nil {
|
||||
return nil;
|
||||
}
|
||||
return fd.Type;
|
||||
|
||||
case *ast.InterfaceType:
|
||||
goto notimpl;
|
||||
@ -173,7 +274,7 @@ func (a *typeCompiler) compileType(x ast.Expr) Type {
|
||||
goto notimpl;
|
||||
|
||||
case *ast.ParenExpr:
|
||||
return a.compileType(x.X);
|
||||
return a.compileType(x.X, allowRec);
|
||||
|
||||
case *ast.Ellipsis:
|
||||
a.diagAt(x, "illegal use of ellipsis");
|
||||
@ -191,12 +292,59 @@ notimpl:
|
||||
* Type compiler interface
|
||||
*/
|
||||
|
||||
func noLateCheck() bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
func (a *compiler) compileType(b *block, typ ast.Expr) Type {
|
||||
tc := &typeCompiler{a, b};
|
||||
return tc.compileType(typ);
|
||||
tc := &typeCompiler{a, b, noLateCheck};
|
||||
t := tc.compileType(typ, false);
|
||||
if !tc.lateCheck() {
|
||||
t = nil;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
|
||||
ok := true;
|
||||
for _, spec := range decl.Specs {
|
||||
spec := spec.(*ast.TypeSpec);
|
||||
// Create incomplete type for this type
|
||||
nt := b.DefineType(spec.Name.Value, spec.Name.Pos(), nil);
|
||||
if nt != nil {
|
||||
nt.(*NamedType).incomplete = true;
|
||||
}
|
||||
// Compile type
|
||||
tc := &typeCompiler{a, b, noLateCheck};
|
||||
t := tc.compileType(spec.Type, false);
|
||||
if t == nil {
|
||||
// Create a placeholder type
|
||||
ok = false;
|
||||
}
|
||||
// Fill incomplete type
|
||||
if nt != nil {
|
||||
nt.(*NamedType).def = t;
|
||||
nt.(*NamedType).incomplete = false;
|
||||
}
|
||||
// Perform late type checking with complete type
|
||||
if !tc.lateCheck() {
|
||||
ok = false;
|
||||
if nt != nil {
|
||||
// Make the type a placeholder
|
||||
nt.(*NamedType).def = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
|
||||
tc := &typeCompiler{a, b};
|
||||
return tc.compileFuncType(typ);
|
||||
tc := &typeCompiler{a, b, noLateCheck};
|
||||
res := tc.compileFuncType(typ, false);
|
||||
if res != nil {
|
||||
if !tc.lateCheck() {
|
||||
res = nil;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -478,6 +478,49 @@ func (t *ArrayType) Zero() Value {
|
||||
return &res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Struct
|
||||
*/
|
||||
|
||||
type structV []Value
|
||||
|
||||
// TODO(austin) Should these methods (and arrayV's) be on structV
|
||||
// instead of *structV?
|
||||
func (v *structV) String() string {
|
||||
res := "{";
|
||||
for i, v := range *v {
|
||||
if i > 0 {
|
||||
res += "; ";
|
||||
}
|
||||
res += v.String();
|
||||
}
|
||||
return res + "}";
|
||||
}
|
||||
|
||||
func (v *structV) Assign(o Value) {
|
||||
oa := o.(StructValue);
|
||||
l := len(*v);
|
||||
for i := 0; i < l; i++ {
|
||||
(*v)[i].Assign(oa.Field(i));
|
||||
}
|
||||
}
|
||||
|
||||
func (v *structV) Get() StructValue {
|
||||
return v;
|
||||
}
|
||||
|
||||
func (v *structV) Field(i int) Value {
|
||||
return (*v)[i];
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
@ -562,8 +605,8 @@ func (v multiV) Assign(o Value) {
|
||||
|
||||
func (t *MultiType) Zero() Value {
|
||||
res := make([]Value, len(t.Elems));
|
||||
for i := 0; i < len(t.Elems); i++ {
|
||||
res[i] = t.Elems[i].Zero();
|
||||
for i, t := range t.Elems {
|
||||
res[i] = t.Zero();
|
||||
}
|
||||
return multiV(res);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user