Type struct;
Block struct;
+ Lit struct;
Expr struct;
Stat struct;
Decl struct;
}
+func (obj* Object) String() string {
+ if obj != nil {
+ return
+ "Object(" +
+ KindStr(obj.Kind) + ", " +
+ obj.Ident +
+ ")";
+ }
+ return "nil";
+}
+
+
var Universe_void_typ *Type // initialized by Universe to Universe.void_typ
var objectId int;
obj.Pos = pos;
obj.Kind = kind;
obj.Ident = ident;
- obj.Typ = Universe_void_typ;
+ obj.Typ = Universe_void_typ; // TODO would it be better to use nil instead?
obj.Pnolev = 0;
return obj;
}
+// ----------------------------------------------------------------------------
+// All nodes have a source position and a token.
+
+type Node struct {
+ Pos int; // source position (< 0 => unknown position)
+ Tok int; // identifying token
+}
+
+
+// ----------------------------------------------------------------------------
+// Literals
+
+type Lit struct {
+ Node;
+
+ // Identifiers
+ Obj *Object;
+
+ // Constant literals
+
+ // Type literals
+ Len *Expr; // array length
+ Dir int; // channel direction
+ Key *Type; // receiver or map key type
+ Elt *Type; // array, map, channel, pointer element, or function result type
+ List *array.Array; End int; // struct fields, interface methods, function parameters
+}
+
+
// ----------------------------------------------------------------------------
// Scopes
}
-// ----------------------------------------------------------------------------
-// All nodes have a source position and and token.
-
-type Node struct {
- Pos int; // source position (< 0 => unknown position)
- Tok int; // identifying token
-}
-
-
// ----------------------------------------------------------------------------
// Blocks
//
// TODO probably don't need the tok parameter eventually
func NewLit(tok int, obj *Object) *Expr {
e := new(Expr);
- e.Pos, e.Tok, e.Obj = obj.Pos, tok, obj;
+ e.Pos, e.Tok, e.Obj, e.Typ = obj.Pos, tok, obj, obj.Typ;
return e;
}
Ref int; // for exporting only: >= 0 means already exported
Form int; // type form
Size int; // size in bytes
- Obj *Object; // primary type object or NULL
+ Obj *Object; // primary type object or nil
Scope *Scope; // locals, fields & methods
// syntactic components
Expr *Expr; // type name, array length
Mode int; // channel mode
Key *Type; // receiver type or map key
- Elt *Type; // array, map, channel or pointer element type, function result type
+ Elt *Type; // type name type, array, map, channel or pointer element type, function result type
List *array.Array; End int; // struct fields, interface methods, function parameters
}
}
+func (typ* Type) String() string {
+ if typ != nil {
+ return
+ "Type(" +
+ FormStr(typ.Form) +
+ ")";
+ }
+ return "nil";
+}
+
+
// requires complete Type.Pos access
func NewTypeExpr(typ *Type) *Expr {
e := new(Expr);
}
+// requires complete Type.String access
+func (x *Expr) String() string {
+ if x != nil {
+ return
+ "Expr(" +
+ Scanner.TokenString(x.Tok) + ", " +
+ x.X.String() + ", " +
+ x.Y.String() + ", " +
+ x.Obj.String() + ", " +
+ x.Typ.String() +
+ ")";
+ }
+ return "nil";
+}
+
+
var BadType = NewType(0, Scanner.ILLEGAL);
Init, Post *Stat;
Expr *Expr;
Body *Block; // composite statement body
- Decl *Decl;
+ Decl *Decl; // declaration statement
}
package Parser
import (
+ "fmt";
"array";
Scanner "scanner";
AST "ast";
}
-func (P *Parser) DeclareInScope(scope *AST.Scope, x *AST.Expr, kind int) {
+func (P *Parser) DeclareInScope(scope *AST.Scope, x *AST.Expr, kind int, typ *AST.Type) {
if P.scope_lev < 0 {
panic("cannot declare objects in other packages");
}
assert(x.Tok == Scanner.IDENT);
obj := x.Obj;
obj.Kind = kind;
+ obj.Typ = typ;
obj.Pnolev = P.scope_lev;
- if scope.LookupLocal(obj.Ident) == nil {
+ switch {
+ case scope.LookupLocal(obj.Ident) == nil:
scope.Insert(obj);
- } else {
+ case kind == AST.TYPE:
+ // possibly a forward declaration
+ case kind == AST.FUNC:
+ // possibly a forward declaration
+ default:
P.Error(obj.Pos, `"` + obj.Ident + `" is declared already`);
}
}
// Declare a comma-separated list of idents or a single ident.
-func (P *Parser) Declare(p *AST.Expr, kind int) {
+func (P *Parser) Declare(p *AST.Expr, kind int, typ *AST.Type) {
for p.Tok == Scanner.COMMA {
- P.DeclareInScope(P.top_scope, p.X, kind);
+ P.DeclareInScope(P.top_scope, p.X, kind, typ);
p = p.Y;
}
- P.DeclareInScope(P.top_scope, p, kind);
+ P.DeclareInScope(P.top_scope, p, kind, typ);
}
t := AST.NewType(P.pos, AST.TYPENAME);
t.Expr = P.ParseQualifiedIdent();
+ t.Elt = t.Expr.Typ;
P.Ecart();
return t;
for i, n := 0, t.List.Len(); i < n; i++ {
x := t.List.At(i).(*AST.Expr);
if x.Tok == Scanner.IDENT {
- P.DeclareInScope(t.Scope, x, AST.FIELD);
+ P.DeclareInScope(t.Scope, x, AST.FIELD, nil);
}
}
}
for i, n := 0, ftyp.List.Len(); i < n; i++ {
x := ftyp.List.At(i).(*AST.Expr);
if x.Tok == Scanner.IDENT {
- P.DeclareInScope(P.top_scope, x, AST.VAR);
+ P.DeclareInScope(P.top_scope, x, AST.VAR, nil);
}
}
}
if P.tok == Scanner.IDENT {
// TODO should always guarantee x.Typ != nil
var scope *AST.Scope;
- if x.Typ != nil {
- scope = x.Typ.Scope;
+ if x.X.Typ != nil {
+ scope = x.X.Typ.Scope;
}
x.Y = P.ParseIdent(scope);
x.Typ = x.Y.Obj.Typ;
P.Expect(Scanner.STRING); // use Expect() error handling
}
- if d.Ident != nil {
- P.Declare(d.Ident, AST.PACKAGE);
- }
-
P.Ecart();
}
d.Val = P.ParseExpressionList();
}
- P.Declare(d.Ident, AST.CONST);
-
P.Ecart();
}
}
}
- P.Declare(d.Ident, AST.VAR);
-
P.Ecart();
}
func (P *Parser) ParseSpec(d *AST.Decl) {
+ kind := AST.NONE;
+
switch d.Tok {
- case Scanner.IMPORT: P.ParseImportSpec(d);
- case Scanner.CONST: P.ParseConstSpec(d);
- case Scanner.TYPE: P.ParseTypeSpec(d);
- case Scanner.VAR: P.ParseVarSpec(d);
+ case Scanner.IMPORT: P.ParseImportSpec(d); kind = AST.PACKAGE;
+ case Scanner.CONST: P.ParseConstSpec(d); kind = AST.CONST;
+ case Scanner.TYPE: P.ParseTypeSpec(d); kind = AST.TYPE;
+ case Scanner.VAR: P.ParseVarSpec(d); kind = AST.VAR;
default: unreachable();
}
-
+
// semantic checks
if d.Tok == Scanner.IMPORT {
- // TODO
- } else {
- if d.Typ != nil {
- // apply type to all variables
+ if d.Ident != nil {
+ P.Declare(d.Ident, kind, nil);
}
+ } else {
+ P.Declare(d.Ident, kind, d.Typ);
if d.Val != nil {
// initialization/assignment
llen := d.Ident.Len();