// 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
// declared pointers across packages yet.
ident string;
typ *Type;
pnolev int; // >= 0: package no., <= 0: level, 0: global level of compilation
+ scope *Scope; // which contains the object
}
len_ int; // array length, no. of parameters (w/o recv)
obj *Object; // primary type object or NULL
key *Type; // maps
- elt *Type; // arrays, maps, channels, pointers
+ elt *Type; // aliases, arrays, maps, channels, pointers
scope *Scope; // structs, interfaces, functions
}
}
+export Expr
+type Expr interface {
+ typ() *Type;
+ // ... more to come here
+}
+
+
+export Stat
+type Stat interface {
+ // ... more to come here
+}
+
+
// ----------------------------------------------------------------------------
// Creation
+export Universe_undef_t
+var Universe_undef_t *Type // initialized by Universe to Universe.undef_t
+
export NewObject
func NewObject(pos, kind int, ident string) *Object {
obj := new(Object);
obj.pos = pos;
obj.kind = kind;
obj.ident = ident;
- obj.typ = nil; // Universe::undef_t; (cyclic import...)
+ obj.typ = Universe_undef_t;
obj.pnolev = 0;
+ obj.scope = nil;
return obj;
}
export NewType
func NewType(form int) *Type {
typ := new(Type);
- typ.ref = -1;
+ typ.ref = -1; // not yet exported
typ.form = form;
return typ;
}
export NewPackage;
func NewPackage(file_name string) *Package {
pkg := new(Package);
- pkg.ref = -1;
+ pkg.ref = -1; // not yet exported
pkg.file_name = file_name;
pkg.key = "<the package key>"; // TODO fix this
return pkg;
}
+// ----------------------------------------------------------------------------
+// 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
var p *Elem;
for p = scope.entries.first; p != nil; p = p.next {
if p.obj.ident == ident {
+ if p.obj.scope != scope {
+ panic "incorrect scope for object";
+ }
return p.obj;
}
}
if scope.Lookup(obj.ident) != nil {
panic "obj already inserted";
}
+ if obj.scope != nil {
+ panic "obj already in a scope";
+ }
scope.entries.AddObj(obj);
+ obj.scope = scope;
}
func MakeFunctionType(sig *Globals.Scope, p0, r0 int, check_recv bool) *Globals.Type {
// Determine if we have a receiver or not.
+ // TODO do we still need this?
if p0 > 0 && check_recv {
// method
if p0 != 1 {
func (P *Parser) TryType() *Globals.Type;
-func (P *Parser) ParseExpression();
+func (P *Parser) ParseExpression() Globals.Expr;
func (P *Parser) TryStatement() bool;
func (P *Parser) ParseDeclaration();
}
+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 {
P.Trace("TypeName");
P.ParseExpression();
}
P.Expect(Scanner.RBRACK);
- typ.elt = P.ParseType();
+ typ.elt = P.ParseVarType();
P.Ecart();
return typ;
default:
typ.flags = Type.SEND + Type.RECV;
}
- typ.elt = P.ParseType();
+ typ.elt = P.ParseVarType();
P.Ecart();
return typ;
P.Trace("VarDeclList");
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 {
p.obj.typ = typ; // TODO should use/have set_type()
}
func (P *Parser) ParseMethodDecl() {
P.Trace("MethodDecl");
- P.ParseIdent();
+ pos := P.pos;
+ ident := P.ParseIdent();
P.OpenScope();
P.level--;
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();
r0 := sig.entries.len_;
P.TryResult();
P.CloseScope();
P.Optional(Scanner.SEMICOLON);
+ obj := Globals.NewObject(pos, Object.FUNC, ident);
+ obj.typ = MakeFunctionType(sig, 1, r0, true);
+ P.Declare(obj);
+
P.Ecart();
}
P.Expect(Scanner.MAP);
P.Expect(Scanner.LBRACK);
typ := Globals.NewType(Type.MAP);
- typ.key = P.ParseType();
+ typ.key = P.ParseVarType();
P.Expect(Scanner.RBRACK);
- typ.elt = P.ParseType();
+ typ.elt = P.ParseVarType();
P.Ecart();
return typ;
P.OpenScope();
if sig != nil {
P.level--;
- // add function parameters to scope
- // TODO do we need to make a copy? what if we change obj fields?
+ // add copies of the formal parameters to the function scope
scope := P.top_scope;
for p := sig.entries.first; p != nil; p = p.next {
- if p.obj.pnolev != P.level {
- panic "incorrect level";
- }
- scope.Insert(p.obj)
+ scope.Insert(p.obj.Copy())
}
}
if P.tok != Scanner.RBRACE && P.tok != Scanner.SEMICOLON {
}
-func (P *Parser) ParseNew() {
+func (P *Parser) ParseNew() Globals.Expr {
P.Trace("New");
P.Expect(Scanner.NEW);
P.Expect(Scanner.RPAREN);
P.Ecart();
+ return nil;
}
-func (P *Parser) ParseFunctionLit() {
+func (P *Parser) ParseFunctionLit() Globals.Expr {
P.Trace("FunctionLit");
typ := P.ParseFunctionType();
P.ParseBlock(typ.scope);
P.Ecart();
+ return nil;
}
}
-func (P *Parser) ParseBuiltinCall() {
+func (P *Parser) ParseBuiltinCall() Globals.Expr {
P.Trace("BuiltinCall");
P.ParseExpressionList(); // TODO should be optional
P.Ecart();
+ return nil;
}
-func (P *Parser) ParseCompositeLit(typ *Globals.Type) {
+func (P *Parser) ParseCompositeLit(typ *Globals.Type) Globals.Expr {
P.Trace("CompositeLit");
// TODO I think we should use {} instead of () for
P.Expect(paren);
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");
if pos < 0 && P.tok == Scanner.IDENT {
exit:
P.Ecart();
+ return nil;
}
-func (P *Parser) ParseSelectorOrTypeAssertion() {
+func (P *Parser) ParseSelectorOrTypeAssertion() Globals.Expr {
P.Trace("SelectorOrTypeAssertion");
P.Expect(Scanner.PERIOD);
}
P.Ecart();
+ return nil;
}
-func (P *Parser) ParseIndexOrSlice() {
+func (P *Parser) ParseIndexOrSlice() Globals.Expr {
P.Trace("IndexOrSlice");
P.Expect(Scanner.LBRACK);
P.Expect(Scanner.RBRACK);
P.Ecart();
+ return nil;
}
-func (P *Parser) ParseCall() {
+func (P *Parser) ParseCall() Globals.Expr {
P.Trace("Call");
P.Expect(Scanner.LPAREN);
P.Expect(Scanner.RPAREN);
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.ParseOperand(pos, ident);
}
-func (P *Parser) ParseUnaryExpr() AST.Expr {
+func (P *Parser) ParseUnaryExpr() Globals.Expr {
P.Trace("UnaryExpr");
switch P.tok {
}
-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");
- var x AST.Expr;
+ var x Globals.Expr;
if pos >= 0 {
x = P.ParsePrimaryExpr(pos, ident);
} else {
for prec := Precedence(P.tok); prec >= prec1; prec-- {
for Precedence(P.tok) == prec {
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.x = x;
P.Next();
}
P.Ecart();
+ return x;
}
// Expressions where the first token may be an identifier which has already
// been consumed. If the identifier is present, pos is the identifier position,
// 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");
indent := P.indent;
- P.ParseBinaryExpr(pos, ident, 1);
+ x := P.ParseBinaryExpr(pos, ident, 1);
if indent != P.indent {
panic "imbalanced tracing code (Expression)";
}
P.Ecart();
+ return x;
}
-func (P *Parser) ParseExpression() {
- P.Trace("Expression");
- P.ParseIdentExpression(-1, "");
+func (P *Parser) ParseExpression() Globals.Expr {
+ P.Trace("Expression");
+
+ x := P.ParseIdentExpression(-1, "");
+
P.Ecart();
+ return x;
}
func (P *Parser) ParseGoStat() {
P.Trace("GoStat");
+
P.Expect(Scanner.GO);
P.ParseExpression();
+
P.Ecart();
}
P.Next();
P.ParseExpressionList();
} else {
- typ := P.ParseType();
+ typ := P.ParseVarType();
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 {
P.Next();