1
0
mirror of https://github.com/golang/go synced 2024-11-23 00:30:07 -07:00

- backward link from objs to containing scope

(first step towards cleaner package handling)
- check that map, function, and channel vars are pointers

R=r
OCL=13690
CL=13690
This commit is contained in:
Robert Griesemer 2008-07-31 13:35:30 -07:00
parent 0c374e9f89
commit 9761a6d069
7 changed files with 151 additions and 72 deletions

View File

@ -11,27 +11,23 @@ import Universe "universe"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Expressions // Expressions
export Expr export BinaryExpr
type Expr interface { type BinaryExpr struct {
typ_ *Globals.Type;
op int;
x, y Globals.Expr;
} }
export BinaryExpr
type BinaryExpr struct { func (x *BinaryExpr) typ() *Globals.Type {
typ *Globals.Type; return x.typ_;
op int;
x, y Expr;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Statements // Statements
export Stat
type Stat interface {
}
export Block export Block
type Block struct { type Block struct {
// TODO fill in // TODO fill in
@ -40,7 +36,7 @@ type Block struct {
export IfStat export IfStat
type IfStat struct { type IfStat struct {
cond Expr; cond Globals.Expr;
then_ Stat; then_ Globals.Stat;
else_ Stat; else_ Globals.Stat;
} }

View File

@ -6,8 +6,7 @@
package decls package decls
//import "base" import "base"
import base "base"
import base2 "base" import base2 "base"
const c0 int = 0 const c0 int = 0
@ -53,12 +52,12 @@ type (
) )
type T6 chan int type T6 chan int
type T7 chan<- T6 type T7 chan<- *T6
type T8 chan-< T6 type T8 chan-< *T6
type T9 struct { type T9 struct {
p *T9; p *T9;
q [] map [int] *T9; q [] *map [int] *T9;
f *func(x, y *T9) *T9; f *func(x, y *T9) *T9;
} }
@ -97,7 +96,7 @@ var v1 float = c1
var ( var (
v2 T2; v2 T2;
v3 struct { v3 struct {
f1, f2, f3 M0; f1, f2, f3 *M0;
} }
) )
@ -105,16 +104,19 @@ var (
func f0() {} func f0() {}
func f1(a int) {} func f1(a int) {}
func f2(a, b int, c float) {} func f2(a, b int, c float) {}
func f3() bool {} func f3() bool { return false; }
func f4(a int) (z T5, ok bool) {} func f4(a int) (z T5, ok bool) {}
func f5(a, b int, c float) (z T5, ok bool) {} func f5(a, b int, c float) (z T5, ok bool) {
u, v := 0, 0;
return;
}
func (p *T4) m0() {} func (p *T4) m0() {}
func (p *T4) m1(a int) {} func (p *T4) m1(a int) {}
func (p *T4) m2(a, b int, c float) {} func (p *T4) m2(a, b int, c float) {}
func (p *T4) m3() bool {} func (p *T4) m3() bool { return false; }
func (p *T4) m4(a int) (z T5, ok bool) {} func (p *T4) m4(a int) (z T5, ok bool) { return; }
func (p *T4) m5(a, b int, c float) (z T5, ok bool) { func (p *T4) m5(a, b int, c float) (z T5, ok bool) {
L: var x = a; L: var x = a;
} }

View File

@ -6,7 +6,7 @@ package Globals
// The following types should really be in their respective files // The following types should really be in their respective files
// (object.go, type.go, scope.go, package.go, compilation.go) but // (object.go, type.go, scope.go, package.go, compilation.go, etc.) but
// they refer to each other and we don't know how to handle forward // they refer to each other and we don't know how to handle forward
// declared pointers across packages yet. // declared pointers across packages yet.
@ -21,6 +21,7 @@ type Object struct {
ident string; ident string;
typ *Type; typ *Type;
pnolev int; // >= 0: package no., <= 0: level, 0: global level of compilation pnolev int; // >= 0: package no., <= 0: level, 0: global level of compilation
scope *Scope; // which contains the object
} }
@ -33,7 +34,7 @@ type Type struct {
len_ int; // array length, no. of parameters (w/o recv) len_ int; // array length, no. of parameters (w/o recv)
obj *Object; // primary type object or NULL obj *Object; // primary type object or NULL
key *Type; // maps key *Type; // maps
elt *Type; // arrays, maps, channels, pointers elt *Type; // aliases, arrays, maps, channels, pointers
scope *Scope; // structs, interfaces, functions scope *Scope; // structs, interfaces, functions
} }
@ -94,9 +95,25 @@ type Compilation struct {
} }
export Expr
type Expr interface {
typ() *Type;
// ... more to come here
}
export Stat
type Stat interface {
// ... more to come here
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Creation // Creation
export Universe_undef_t
var Universe_undef_t *Type // initialized by Universe to Universe.undef_t
export NewObject export NewObject
func NewObject(pos, kind int, ident string) *Object { func NewObject(pos, kind int, ident string) *Object {
obj := new(Object); obj := new(Object);
@ -104,8 +121,9 @@ func NewObject(pos, kind int, ident string) *Object {
obj.pos = pos; obj.pos = pos;
obj.kind = kind; obj.kind = kind;
obj.ident = ident; obj.ident = ident;
obj.typ = nil; // Universe::undef_t; (cyclic import...) obj.typ = Universe_undef_t;
obj.pnolev = 0; obj.pnolev = 0;
obj.scope = nil;
return obj; return obj;
} }
@ -113,7 +131,7 @@ func NewObject(pos, kind int, ident string) *Object {
export NewType export NewType
func NewType(form int) *Type { func NewType(form int) *Type {
typ := new(Type); typ := new(Type);
typ.ref = -1; typ.ref = -1; // not yet exported
typ.form = form; typ.form = form;
return typ; return typ;
} }
@ -122,7 +140,7 @@ func NewType(form int) *Type {
export NewPackage; export NewPackage;
func NewPackage(file_name string) *Package { func NewPackage(file_name string) *Package {
pkg := new(Package); pkg := new(Package);
pkg.ref = -1; pkg.ref = -1; // not yet exported
pkg.file_name = file_name; pkg.file_name = file_name;
pkg.key = "<the package key>"; // TODO fix this pkg.key = "<the package key>"; // TODO fix this
return pkg; return pkg;
@ -152,6 +170,22 @@ func NewCompilation(flags *Flags) *Compilation {
} }
// ----------------------------------------------------------------------------
// Object methods
func (obj *Object) Copy() *Object {
copy := new(Object);
copy.exported = obj.exported;
copy.pos = obj.pos;
copy.kind = obj.kind;
copy.ident = obj.ident;
copy.typ = obj.typ;
copy.pnolev = obj.pnolev;
copy.scope = nil; // cannot be in the same scope (same ident!)
return copy;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// List methods // List methods
@ -239,6 +273,9 @@ func (scope *Scope) Lookup(ident string) *Object {
var p *Elem; var p *Elem;
for p = scope.entries.first; p != nil; p = p.next { for p = scope.entries.first; p != nil; p = p.next {
if p.obj.ident == ident { if p.obj.ident == ident {
if p.obj.scope != scope {
panic "incorrect scope for object";
}
return p.obj; return p.obj;
} }
} }
@ -250,7 +287,11 @@ func (scope *Scope) Insert(obj *Object) {
if scope.Lookup(obj.ident) != nil { if scope.Lookup(obj.ident) != nil {
panic "obj already inserted"; panic "obj already inserted";
} }
if obj.scope != nil {
panic "obj already in a scope";
}
scope.entries.AddObj(obj); scope.entries.AddObj(obj);
obj.scope = scope;
} }

View File

@ -149,6 +149,7 @@ func (P *Parser) Declare(obj *Globals.Object) {
func MakeFunctionType(sig *Globals.Scope, p0, r0 int, check_recv bool) *Globals.Type { func MakeFunctionType(sig *Globals.Scope, p0, r0 int, check_recv bool) *Globals.Type {
// Determine if we have a receiver or not. // Determine if we have a receiver or not.
// TODO do we still need this?
if p0 > 0 && check_recv { if p0 > 0 && check_recv {
// method // method
if p0 != 1 { if p0 != 1 {
@ -223,7 +224,7 @@ func (P *Parser) DeclareFunc(ident string, typ *Globals.Type) *Globals.Object {
func (P *Parser) TryType() *Globals.Type; func (P *Parser) TryType() *Globals.Type;
func (P *Parser) ParseExpression(); func (P *Parser) ParseExpression() Globals.Expr;
func (P *Parser) TryStatement() bool; func (P *Parser) TryStatement() bool;
func (P *Parser) ParseDeclaration(); func (P *Parser) ParseDeclaration();
@ -350,6 +351,32 @@ func (P *Parser) ParseType() *Globals.Type {
} }
func (P *Parser) ParseVarType() *Globals.Type {
P.Trace("VarType");
pos := P.pos;
typ := P.ParseType();
if P.semantic_checks {
switch typ.form {
case Type.ARRAY:
if P.comp.flags.sixg || typ.len_ >= 0 {
break;
}
// open arrays must be pointers
fallthrough;
case Type.MAP, Type.CHANNEL, Type.FUNCTION:
P.Error(pos, "must be pointer to this type");
typ = Universe.bad_t;
}
}
P.Ecart();
return typ;
}
func (P *Parser) ParseTypeName() *Globals.Type { func (P *Parser) ParseTypeName() *Globals.Type {
P.Trace("TypeName"); P.Trace("TypeName");
@ -381,7 +408,7 @@ func (P *Parser) ParseArrayType() *Globals.Type {
P.ParseExpression(); P.ParseExpression();
} }
P.Expect(Scanner.RBRACK); P.Expect(Scanner.RBRACK);
typ.elt = P.ParseType(); typ.elt = P.ParseVarType();
P.Ecart(); P.Ecart();
return typ; return typ;
@ -403,7 +430,7 @@ func (P *Parser) ParseChannelType() *Globals.Type {
default: default:
typ.flags = Type.SEND + Type.RECV; typ.flags = Type.SEND + Type.RECV;
} }
typ.elt = P.ParseType(); typ.elt = P.ParseVarType();
P.Ecart(); P.Ecart();
return typ; return typ;
@ -414,7 +441,7 @@ func (P *Parser) ParseVarDeclList() {
P.Trace("VarDeclList"); P.Trace("VarDeclList");
list := P.ParseIdentDeclList(Object.VAR); list := P.ParseIdentDeclList(Object.VAR);
typ := P.ParseType(); // TODO should check completeness of types typ := P.ParseVarType();
for p := list.first; p != nil; p = p.next { for p := list.first; p != nil; p = p.next {
p.obj.typ = typ; // TODO should use/have set_type() p.obj.typ = typ; // TODO should use/have set_type()
} }
@ -571,11 +598,13 @@ func (P *Parser) ParseFunctionType() *Globals.Type {
func (P *Parser) ParseMethodDecl() { func (P *Parser) ParseMethodDecl() {
P.Trace("MethodDecl"); P.Trace("MethodDecl");
P.ParseIdent(); pos := P.pos;
ident := P.ParseIdent();
P.OpenScope(); P.OpenScope();
P.level--; P.level--;
sig := P.top_scope; sig := P.top_scope;
p0 := 0; // dummy receiver (give it a name so it won't conflict with unnamed result)
sig.Insert(Globals.NewObject(pos, Object.VAR, ".recv"));
P.ParseParameters(); P.ParseParameters();
r0 := sig.entries.len_; r0 := sig.entries.len_;
P.TryResult(); P.TryResult();
@ -583,6 +612,10 @@ func (P *Parser) ParseMethodDecl() {
P.CloseScope(); P.CloseScope();
P.Optional(Scanner.SEMICOLON); P.Optional(Scanner.SEMICOLON);
obj := Globals.NewObject(pos, Object.FUNC, ident);
obj.typ = MakeFunctionType(sig, 1, r0, true);
P.Declare(obj);
P.Ecart(); P.Ecart();
} }
@ -614,9 +647,9 @@ func (P *Parser) ParseMapType() *Globals.Type {
P.Expect(Scanner.MAP); P.Expect(Scanner.MAP);
P.Expect(Scanner.LBRACK); P.Expect(Scanner.LBRACK);
typ := Globals.NewType(Type.MAP); typ := Globals.NewType(Type.MAP);
typ.key = P.ParseType(); typ.key = P.ParseVarType();
P.Expect(Scanner.RBRACK); P.Expect(Scanner.RBRACK);
typ.elt = P.ParseType(); typ.elt = P.ParseVarType();
P.Ecart(); P.Ecart();
return typ; return typ;
@ -754,14 +787,10 @@ func (P *Parser) ParseBlock(sig *Globals.Scope) {
P.OpenScope(); P.OpenScope();
if sig != nil { if sig != nil {
P.level--; P.level--;
// add function parameters to scope // add copies of the formal parameters to the function scope
// TODO do we need to make a copy? what if we change obj fields?
scope := P.top_scope; scope := P.top_scope;
for p := sig.entries.first; p != nil; p = p.next { for p := sig.entries.first; p != nil; p = p.next {
if p.obj.pnolev != P.level { scope.Insert(p.obj.Copy())
panic "incorrect level";
}
scope.Insert(p.obj)
} }
} }
if P.tok != Scanner.RBRACE && P.tok != Scanner.SEMICOLON { if P.tok != Scanner.RBRACE && P.tok != Scanner.SEMICOLON {
@ -798,7 +827,7 @@ func (P *Parser) ParseExpressionList() *Globals.List {
} }
func (P *Parser) ParseNew() { func (P *Parser) ParseNew() Globals.Expr {
P.Trace("New"); P.Trace("New");
P.Expect(Scanner.NEW); P.Expect(Scanner.NEW);
@ -811,16 +840,18 @@ func (P *Parser) ParseNew() {
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RPAREN);
P.Ecart(); P.Ecart();
return nil;
} }
func (P *Parser) ParseFunctionLit() { func (P *Parser) ParseFunctionLit() Globals.Expr {
P.Trace("FunctionLit"); P.Trace("FunctionLit");
typ := P.ParseFunctionType(); typ := P.ParseFunctionType();
P.ParseBlock(typ.scope); P.ParseBlock(typ.scope);
P.Ecart(); P.Ecart();
return nil;
} }
@ -847,16 +878,17 @@ func (P *Parser) ParseExpressionPairList() {
} }
func (P *Parser) ParseBuiltinCall() { func (P *Parser) ParseBuiltinCall() Globals.Expr {
P.Trace("BuiltinCall"); P.Trace("BuiltinCall");
P.ParseExpressionList(); // TODO should be optional P.ParseExpressionList(); // TODO should be optional
P.Ecart(); P.Ecart();
return nil;
} }
func (P *Parser) ParseCompositeLit(typ *Globals.Type) { func (P *Parser) ParseCompositeLit(typ *Globals.Type) Globals.Expr {
P.Trace("CompositeLit"); P.Trace("CompositeLit");
// TODO I think we should use {} instead of () for // TODO I think we should use {} instead of () for
@ -894,10 +926,11 @@ func (P *Parser) ParseCompositeLit(typ *Globals.Type) {
P.Expect(paren); P.Expect(paren);
P.Ecart(); P.Ecart();
return nil;
} }
func (P *Parser) ParseOperand(pos int, ident string) { func (P *Parser) ParseOperand(pos int, ident string) Globals.Expr {
P.Trace("Operand"); P.Trace("Operand");
if pos < 0 && P.tok == Scanner.IDENT { if pos < 0 && P.tok == Scanner.IDENT {
@ -954,10 +987,11 @@ func (P *Parser) ParseOperand(pos int, ident string) {
exit: exit:
P.Ecart(); P.Ecart();
return nil;
} }
func (P *Parser) ParseSelectorOrTypeAssertion() { func (P *Parser) ParseSelectorOrTypeAssertion() Globals.Expr {
P.Trace("SelectorOrTypeAssertion"); P.Trace("SelectorOrTypeAssertion");
P.Expect(Scanner.PERIOD); P.Expect(Scanner.PERIOD);
@ -970,10 +1004,11 @@ func (P *Parser) ParseSelectorOrTypeAssertion() {
} }
P.Ecart(); P.Ecart();
return nil;
} }
func (P *Parser) ParseIndexOrSlice() { func (P *Parser) ParseIndexOrSlice() Globals.Expr {
P.Trace("IndexOrSlice"); P.Trace("IndexOrSlice");
P.Expect(Scanner.LBRACK); P.Expect(Scanner.LBRACK);
@ -985,10 +1020,11 @@ func (P *Parser) ParseIndexOrSlice() {
P.Expect(Scanner.RBRACK); P.Expect(Scanner.RBRACK);
P.Ecart(); P.Ecart();
return nil;
} }
func (P *Parser) ParseCall() { func (P *Parser) ParseCall() Globals.Expr {
P.Trace("Call"); P.Trace("Call");
P.Expect(Scanner.LPAREN); P.Expect(Scanner.LPAREN);
@ -998,10 +1034,11 @@ func (P *Parser) ParseCall() {
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RPAREN);
P.Ecart(); P.Ecart();
return nil;
} }
func (P *Parser) ParsePrimaryExpr(pos int, ident string) AST.Expr { func (P *Parser) ParsePrimaryExpr(pos int, ident string) Globals.Expr {
P.Trace("PrimaryExpr"); P.Trace("PrimaryExpr");
P.ParseOperand(pos, ident); P.ParseOperand(pos, ident);
@ -1037,7 +1074,7 @@ func (P *Parser) ParsePrimaryExprList() {
} }
func (P *Parser) ParseUnaryExpr() AST.Expr { func (P *Parser) ParseUnaryExpr() Globals.Expr {
P.Trace("UnaryExpr"); P.Trace("UnaryExpr");
switch P.tok { switch P.tok {
@ -1080,10 +1117,10 @@ func Precedence(tok int) int {
} }
func (P *Parser) ParseBinaryExpr(pos int, ident string, prec1 int) AST.Expr { func (P *Parser) ParseBinaryExpr(pos int, ident string, prec1 int) Globals.Expr {
P.Trace("BinaryExpr"); P.Trace("BinaryExpr");
var x AST.Expr; var x Globals.Expr;
if pos >= 0 { if pos >= 0 {
x = P.ParsePrimaryExpr(pos, ident); x = P.ParsePrimaryExpr(pos, ident);
} else { } else {
@ -1092,7 +1129,7 @@ func (P *Parser) ParseBinaryExpr(pos int, ident string, prec1 int) AST.Expr {
for prec := Precedence(P.tok); prec >= prec1; prec-- { for prec := Precedence(P.tok); prec >= prec1; prec-- {
for Precedence(P.tok) == prec { for Precedence(P.tok) == prec {
e := new(AST.BinaryExpr); e := new(AST.BinaryExpr);
e.typ = Universe.undef_t; // TODO fix this e.typ_ = Universe.undef_t; // TODO fix this
e.op = P.tok; // TODO should we use tokens or separate operator constants? e.op = P.tok; // TODO should we use tokens or separate operator constants?
e.x = x; e.x = x;
P.Next(); P.Next();
@ -1102,29 +1139,34 @@ func (P *Parser) ParseBinaryExpr(pos int, ident string, prec1 int) AST.Expr {
} }
P.Ecart(); P.Ecart();
return x;
} }
// Expressions where the first token may be an identifier which has already // Expressions where the first token may be an identifier which has already
// been consumed. If the identifier is present, pos is the identifier position, // been consumed. If the identifier is present, pos is the identifier position,
// otherwise pos must be < 0 (and ident is ignored). // otherwise pos must be < 0 (and ident is ignored).
func (P *Parser) ParseIdentExpression(pos int, ident string) { func (P *Parser) ParseIdentExpression(pos int, ident string) Globals.Expr {
P.Trace("IdentExpression"); P.Trace("IdentExpression");
indent := P.indent; indent := P.indent;
P.ParseBinaryExpr(pos, ident, 1); x := P.ParseBinaryExpr(pos, ident, 1);
if indent != P.indent { if indent != P.indent {
panic "imbalanced tracing code (Expression)"; panic "imbalanced tracing code (Expression)";
} }
P.Ecart(); P.Ecart();
return x;
} }
func (P *Parser) ParseExpression() { func (P *Parser) ParseExpression() Globals.Expr {
P.Trace("Expression"); P.Trace("Expression");
P.ParseIdentExpression(-1, "");
x := P.ParseIdentExpression(-1, "");
P.Ecart(); P.Ecart();
return x;
} }
@ -1280,8 +1322,10 @@ func (P *Parser) ParseSimpleStat() {
func (P *Parser) ParseGoStat() { func (P *Parser) ParseGoStat() {
P.Trace("GoStat"); P.Trace("GoStat");
P.Expect(Scanner.GO); P.Expect(Scanner.GO);
P.ParseExpression(); P.ParseExpression();
P.Ecart(); P.Ecart();
} }
@ -1666,9 +1710,9 @@ func (P *Parser) ParseVarSpec(exported bool) {
P.Next(); P.Next();
P.ParseExpressionList(); P.ParseExpressionList();
} else { } else {
typ := P.ParseType(); typ := P.ParseVarType();
for p := list.first; p != nil; p = p.next { for p := list.first; p != nil; p = p.next {
p.obj.typ = typ; // TODO should use/have set_type()! p.obj.typ = typ;
} }
if P.tok == Scanner.ASSIGN { if P.tok == Scanner.ASSIGN {
P.Next(); P.Next();

View File

@ -79,7 +79,7 @@ func (P *Printer) PrintSignature(typ *Globals.Type, fun *Globals.Object) {
if fun != nil { if fun != nil {
P.PrintObject(fun); P.PrintObject(fun);
print " "; //print " ";
} else if p0 > 0 { } else if p0 > 0 {
print ". "; print ". ";
} }
@ -94,10 +94,9 @@ func (P *Printer) PrintSignature(typ *Globals.Type, fun *Globals.Object) {
func (P *Printer) PrintIndent() { func (P *Printer) PrintIndent() {
const scale = 4;
print "\n"; print "\n";
for i := P.level * scale; i > 0; i-- { for i := P.level; i > 0; i-- {
print " "; print "\t";
} }
} }

View File

@ -109,6 +109,7 @@ func init() {
// Interal types // Interal types
undef_t = Globals.NewType(Type.UNDEF); undef_t = Globals.NewType(Type.UNDEF);
Globals.Universe_undef_t = undef_t;
bad_t = Globals.NewType(Type.BAD); bad_t = Globals.NewType(Type.BAD);
nil_t = DeclType(Type.NIL, "nil", 8); nil_t = DeclType(Type.NIL, "nil", 8);

View File

@ -25,10 +25,6 @@ func VerifyObject(obj *Globals.Object, pnolev int);
func VerifyType(typ *Globals.Type) { func VerifyType(typ *Globals.Type) {
if typ == nil {
return; // see Globals.NewObject
}
if typ.obj != nil { if typ.obj != nil {
VerifyObject(typ.obj, 0); VerifyObject(typ.obj, 0);
} }