}
-func (P *Parser) Lookup(ident string) *Globals.Object {
- for scope := P.top_scope; scope != nil; scope = scope.parent {
+func Lookup(scope *Globals.Scope, ident string) *Globals.Object {
+ for scope != nil {
obj := scope.Lookup(ident);
if obj != nil {
return obj;
}
+ scope = scope.parent;
}
return nil;
}
func (P *Parser) ParseDeclaration() *AST.Decl;
-func (P *Parser) ParseIdent() *AST.Expr {
+// If scope != nil, lookup identifier in scope. Otherwise create one.
+func (P *Parser) ParseIdent(scope *Globals.Scope) *AST.Expr {
P.Trace("Ident");
-
+
x := AST.BadExpr;
if P.tok == Scanner.IDENT {
- obj := Globals.NewObject(P.pos, Object.NONE, P.val);
+ var obj *Globals.Object;
+ if scope != nil {
+ obj = Lookup(scope, P.val);
+ }
+ if obj == nil {
+ obj = Globals.NewObject(P.pos, Object.NONE, P.val);
+ } else {
+ assert(obj.kind != Object.NONE);
+ }
x = AST.NewLit(P.pos, Scanner.IDENT, obj);
if P.verbose {
P.PrintIndent();
- print("Ident = \"", x.obj.ident, "\"\n");
+ print("Ident = \"", P.val, "\"\n");
}
P.Next();
} else {
P.Trace("IdentList");
var last *AST.Expr;
- x := P.ParseIdent();
+ x := P.ParseIdent(nil);
for P.tok == Scanner.COMMA {
pos := P.pos;
P.Next();
- y := P.ParseIdent();
+ y := P.ParseIdent(nil);
if last == nil {
x = P.NewExpr(pos, Scanner.COMMA, x, y);
last = x;
func (P *Parser) ParseQualifiedIdent() *AST.Expr {
P.Trace("QualifiedIdent");
- x := P.ParseIdent();
+ x := P.ParseIdent(P.top_scope);
for P.tok == Scanner.PERIOD {
pos := P.pos;
P.Next();
- y := P.ParseIdent();
+ y := P.ParseIdent(nil);
x = P.NewExpr(pos, Scanner.PERIOD, x, y);
}
func (P *Parser) ParseVarDecl(expect_ident bool) *AST.Type {
t := AST.BadType;
if expect_ident {
- x := P.ParseIdent();
+ x := P.ParseIdent(nil);
t = AST.NewType(x.pos, Scanner.IDENT);
t.expr = x;
} else if P.tok == Scanner.ELLIPSIS {
x := AST.BadExpr;
switch P.tok {
case Scanner.IDENT:
- x = P.ParseIdent();
+ x = P.ParseIdent(P.top_scope);
case Scanner.LPAREN:
// TODO we could have a function type here as in: new(())
P.Expect(Scanner.PERIOD);
if P.tok == Scanner.IDENT {
- x.y = P.ParseIdent();
+ x.y = P.ParseIdent(nil);
} else {
P.Expect(Scanner.LPAREN);
case Scanner.LPAREN: x = P.ParseCall(x);
case Scanner.LBRACE:
// assume a composite literal only if x could be a type
- // and if we are not inside control clause (expr_lev >= 0)
+ // and if we are not inside a control clause (expr_lev >= 0)
// (composites inside control clauses must be parenthesized)
var t *AST.Type;
if P.expr_lev >= 0 {
s := AST.NewStat(P.pos, tok);
P.Expect(tok);
if tok != Scanner.FALLTHROUGH && P.tok == Scanner.IDENT {
- s.expr = P.ParseIdent();
+ s.expr = P.ParseIdent(P.top_scope);
}
P.Ecart();
P.Error(P.pos, `"import ." not yet handled properly`);
P.Next();
} else if P.tok == Scanner.IDENT {
- d.ident = P.ParseIdent();
+ d.ident = P.ParseIdent(nil);
}
if P.tok == Scanner.STRING {
P.Trace("TypeSpec");
d := AST.NewDecl(pos, Scanner.TYPE, exported);
- d.ident = P.ParseIdent();
+ d.ident = P.ParseIdent(nil);
d.typ = P.ParseType();
P.opt_semi = true;
}
}
- d.ident = P.ParseIdent();
+ d.ident = P.ParseIdent(nil);
d.typ = P.ParseFunctionType();
d.typ.key = recv;
P.OpenScope();
p := AST.NewProgram(P.pos);
P.Expect(Scanner.PACKAGE);
- p.ident = P.ParseIdent();
+ p.ident = P.ParseIdent(nil);
// package body
{ P.OpenScope();
"tabwriter";
"flag";
"fmt";
+ Utils "utils";
Globals "globals";
Object "object";
Scanner "scanner";
var esc string;
for i := 0; i < len(s); i++ {
switch s[i] {
- case '<': esc = "<";
- case '&': esc = "&";
+ case '<': esc = "<";
+ case '&': esc = "&";
default: continue;
}
return s[0 : i] + esc + HtmlEscape(s[i+1 : len(s)]);
}
-func (P *Printer) HtmlIdentifier(pos int, obj *Globals.Object) {
- if html.BVal() {
- // no need to HtmlEscape ident
- P.TaggedString(pos, `<a href="#` + obj.ident + `">`, obj.ident, `</a>`);
+func (P *Printer) HtmlIdentifier(x *AST.Expr) {
+ if x.tok != Scanner.IDENT {
+ panic();
+ }
+ obj := x.obj;
+ if html.BVal() && obj.kind != Object.NONE {
+ // depending on whether we have a declaration or use, generate different html
+ // - no need to HtmlEscape ident
+ id := Utils.IntToString(obj.id, 10);
+ if x.pos == obj.pos {
+ // probably the declaration of x
+ P.TaggedString(x.pos, `<a name="id` + id + `">`, obj.ident, `</a>`);
+ } else {
+ // probably not the declaration of x
+ P.TaggedString(x.pos, `<a href="#id` + id + `">`, obj.ident, `</a>`);
+ }
} else {
- P.String(pos, obj.ident);
+ P.String(x.pos, obj.ident);
}
}
P.Type(x.t);
case Scanner.IDENT:
- P.HtmlIdentifier(x.pos, x.obj);
+ P.HtmlIdentifier(x);
case Scanner.INT, Scanner.STRING, Scanner.FLOAT:
// literal
text := tabwriter.New(os.Stdout, int(tabwidth.IVal()), 1, padchar, true, html.BVal());
P.Init(text, prog.comments);
- P.HtmlPrologue("<the source>");
+ // TODO would be better to make the name of the src file be the title
+ P.HtmlPrologue("package " + prog.ident.obj.ident);
P.Program(prog);
P.HtmlEpilogue();