Commit 01b4f2dd authored by Robert Griesemer's avatar Robert Griesemer

Steps towards tracking scopes for identifiers.

	- Identifiers refer now to the language entity (Object)
	  that they denote. At the moment this is at best an
	  approximation.

	- Initial data structures for language entities (Objects)
          and expression types (Type) independent of the actual
	  type notations.

	- Initial support for declaring and looking up identifiers.

	- Updated various dependent files and added support functions.

	- Extensively tested to avoid breakage. This is an AST change.

R=rsc
CC=golang-dev, rog
https://golang.org/cl/189080
parent 67237c0f
...@@ -74,7 +74,7 @@ func openProg(name string, p *Prog) { ...@@ -74,7 +74,7 @@ func openProg(name string, p *Prog) {
} }
fatal("parsing %s: %s", name, err) fatal("parsing %s: %s", name, err)
} }
p.Package = p.AST.Name.Value p.Package = p.AST.Name.Name()
// Find the import "C" line and get any extra C preamble. // Find the import "C" line and get any extra C preamble.
// Delete the import "C" line along the way. // Delete the import "C" line along the way.
...@@ -134,7 +134,7 @@ func walk(x interface{}, p *Prog, context string) { ...@@ -134,7 +134,7 @@ func walk(x interface{}, p *Prog, context string) {
// The parser should take care of scoping in the future, // The parser should take care of scoping in the future,
// so that we will be able to distinguish a "top-level C" // so that we will be able to distinguish a "top-level C"
// from a local C. // from a local C.
if l, ok := sel.X.(*ast.Ident); ok && l.Value == "C" { if l, ok := sel.X.(*ast.Ident); ok && l.Name() == "C" {
i := len(p.Crefs) i := len(p.Crefs)
if i >= cap(p.Crefs) { if i >= cap(p.Crefs) {
new := make([]*Cref, 2*i) new := make([]*Cref, 2*i)
...@@ -145,7 +145,7 @@ func walk(x interface{}, p *Prog, context string) { ...@@ -145,7 +145,7 @@ func walk(x interface{}, p *Prog, context string) {
} }
p.Crefs = p.Crefs[0 : i+1] p.Crefs = p.Crefs[0 : i+1]
p.Crefs[i] = &Cref{ p.Crefs[i] = &Cref{
Name: sel.Sel.Value, Name: sel.Sel.Name(),
Expr: n, Expr: n,
Context: context, Context: context,
} }
......
...@@ -559,7 +559,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -559,7 +559,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.Go = name // publish before recursive calls t.Go = name // publish before recursive calls
switch dt.Kind { switch dt.Kind {
case "union", "class": case "union", "class":
c.typedef[name.Value] = c.Opaque(t.Size) c.typedef[name.Name()] = c.Opaque(t.Size)
if t.C == "" { if t.C == "" {
t.C = fmt.Sprintf("typeof(unsigned char[%d])", t.Size) t.C = fmt.Sprintf("typeof(unsigned char[%d])", t.Size)
} }
...@@ -569,7 +569,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -569,7 +569,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.C = csyntax t.C = csyntax
} }
t.Align = align t.Align = align
c.typedef[name.Value] = g c.typedef[name.Name()] = g
} }
case *dwarf.TypedefType: case *dwarf.TypedefType:
...@@ -588,8 +588,8 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -588,8 +588,8 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
sub := c.Type(dt.Type) sub := c.Type(dt.Type)
t.Size = sub.Size t.Size = sub.Size
t.Align = sub.Align t.Align = sub.Align
if _, ok := c.typedef[name.Value]; !ok { if _, ok := c.typedef[name.Name()]; !ok {
c.typedef[name.Value] = sub.Go c.typedef[name.Name()] = sub.Go
} }
case *dwarf.UcharType: case *dwarf.UcharType:
...@@ -633,7 +633,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -633,7 +633,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
} }
s = strings.Join(strings.Split(s, " ", 0), "") // strip spaces s = strings.Join(strings.Split(s, " ", 0), "") // strip spaces
name := c.Ident("_C_" + s) name := c.Ident("_C_" + s)
c.typedef[name.Value] = t.Go c.typedef[name.Name()] = t.Go
t.Go = name t.Go = name
} }
} }
...@@ -710,7 +710,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType { ...@@ -710,7 +710,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
} }
// Identifier // Identifier
func (c *typeConv) Ident(s string) *ast.Ident { return &ast.Ident{Value: s} } func (c *typeConv) Ident(s string) *ast.Ident { return ast.NewIdent(s) }
// Opaque type of n bytes. // Opaque type of n bytes.
func (c *typeConv) Opaque(n int64) ast.Expr { func (c *typeConv) Opaque(n int64) ast.Expr {
......
...@@ -94,13 +94,13 @@ func main() { ...@@ -94,13 +94,13 @@ func main() {
switch cref.Context { switch cref.Context {
case "const": case "const":
// This came from a #define and we'll output it later. // This came from a #define and we'll output it later.
*cref.Expr = &ast.Ident{Value: cref.Name} *cref.Expr = ast.NewIdent(cref.Name)
break break
case "call": case "call":
if !cref.TypeName { if !cref.TypeName {
// Is an actual function call. // Is an actual function call.
pos := (*cref.Expr).Pos() pos := (*cref.Expr).Pos()
*cref.Expr = &ast.Ident{Position: pos, Value: "_C_" + cref.Name} *cref.Expr = &ast.Ident{Position: pos, Obj: ast.NewObj(ast.Err, pos, "_C_"+cref.Name)}
p.Funcdef[cref.Name] = cref.FuncType p.Funcdef[cref.Name] = cref.FuncType
break break
} }
...@@ -113,13 +113,13 @@ func main() { ...@@ -113,13 +113,13 @@ func main() {
// place the identifier for the value and add it to Enumdef so // place the identifier for the value and add it to Enumdef so
// it will be declared as a constant in the later stage. // it will be declared as a constant in the later stage.
if cref.Type.EnumValues != nil { if cref.Type.EnumValues != nil {
*cref.Expr = &ast.Ident{Value: cref.Name} *cref.Expr = ast.NewIdent(cref.Name)
p.Enumdef[cref.Name] = cref.Type.EnumValues[cref.Name] p.Enumdef[cref.Name] = cref.Type.EnumValues[cref.Name]
break break
} }
// Reference to C variable. // Reference to C variable.
// We declare a pointer and arrange to have it filled in. // We declare a pointer and arrange to have it filled in.
*cref.Expr = &ast.StarExpr{X: &ast.Ident{Value: "_C_" + cref.Name}} *cref.Expr = &ast.StarExpr{X: ast.NewIdent("_C_" + cref.Name)}
p.Vardef[cref.Name] = cref.Type p.Vardef[cref.Name] = cref.Type
case "type": case "type":
if !cref.TypeName { if !cref.TypeName {
......
...@@ -69,7 +69,7 @@ func (p *Prog) writeDefs() { ...@@ -69,7 +69,7 @@ func (p *Prog) writeDefs() {
for name, def := range p.Funcdef { for name, def := range p.Funcdef {
// Go func declaration. // Go func declaration.
d := &ast.FuncDecl{ d := &ast.FuncDecl{
Name: &ast.Ident{Value: "_C_" + name}, Name: ast.NewIdent("_C_" + name),
Type: def.Go, Type: def.Go,
} }
printer.Fprint(fgo2, d) printer.Fprint(fgo2, d)
......
...@@ -126,7 +126,7 @@ func pkgName(filename string) string { ...@@ -126,7 +126,7 @@ func pkgName(filename string) string {
if err != nil || file == nil { if err != nil || file == nil {
return "" return ""
} }
return file.Name.Value return file.Name.Name()
} }
...@@ -215,7 +215,7 @@ func newDirTree(path, name string, depth, maxDepth int) *Directory { ...@@ -215,7 +215,7 @@ func newDirTree(path, name string, depth, maxDepth int) *Directory {
// (left-over) "documentation" package somewhere in a package // (left-over) "documentation" package somewhere in a package
// directory of different name, but this is very unlikely and // directory of different name, but this is very unlikely and
// against current conventions. // against current conventions.
(file.Name.Value == name || file.Name.Value == fakePkgName) && (file.Name.Name() == name || file.Name.Name() == fakePkgName) &&
file.Doc != nil { file.Doc != nil {
// found documentation; extract a synopsys // found documentation; extract a synopsys
text = firstSentence(doc.CommentText(file.Doc)) text = firstSentence(doc.CommentText(file.Doc))
...@@ -439,8 +439,8 @@ func (s *Styler) BasicLit(x *ast.BasicLit) (text []byte, tag printer.HTMLTag) { ...@@ -439,8 +439,8 @@ func (s *Styler) BasicLit(x *ast.BasicLit) (text []byte, tag printer.HTMLTag) {
func (s *Styler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) { func (s *Styler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) {
text = strings.Bytes(id.Value) text = strings.Bytes(id.Name())
if s.highlight == id.Value { if s.highlight == id.Name() {
tag = printer.HTMLTag{"<span class=highlight>", "</span>"} tag = printer.HTMLTag{"<span class=highlight>", "</span>"}
} }
return return
......
...@@ -452,10 +452,10 @@ func (x *Indexer) visitComment(c *ast.CommentGroup) { ...@@ -452,10 +452,10 @@ func (x *Indexer) visitComment(c *ast.CommentGroup) {
func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) { func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
if id != nil { if id != nil {
lists, found := x.words[id.Value] lists, found := x.words[id.Name()]
if !found { if !found {
lists = new(IndexResult) lists = new(IndexResult)
x.words[id.Value] = lists x.words[id.Name()] = lists
} }
if kind == Use || x.decl == nil { if kind == Use || x.decl == nil {
...@@ -606,7 +606,7 @@ func (x *Indexer) VisitFile(path string, d *os.Dir) { ...@@ -606,7 +606,7 @@ func (x *Indexer) VisitFile(path string, d *os.Dir) {
} }
dir, _ := pathutil.Split(path) dir, _ := pathutil.Split(path)
pak := Pak{dir, file.Name.Value} pak := Pak{dir, file.Name.Name()}
x.file = &File{path, pak} x.file = &File{path, pak}
ast.Walk(x, file) ast.Walk(x, file)
} }
......
...@@ -36,7 +36,7 @@ func (s *snippetStyler) LineTag(line int) (text []uint8, tag printer.HTMLTag) { ...@@ -36,7 +36,7 @@ func (s *snippetStyler) LineTag(line int) (text []uint8, tag printer.HTMLTag) {
func (s *snippetStyler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) { func (s *snippetStyler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) {
text = strings.Bytes(id.Value) text = strings.Bytes(id.Name())
if s.highlight == id { if s.highlight == id {
tag = printer.HTMLTag{"<span class=highlight>", "</span>"} tag = printer.HTMLTag{"<span class=highlight>", "</span>"}
} }
...@@ -115,7 +115,7 @@ func NewSnippet(decl ast.Decl, id *ast.Ident) (s *Snippet) { ...@@ -115,7 +115,7 @@ func NewSnippet(decl ast.Decl, id *ast.Ident) (s *Snippet) {
if s == nil { if s == nil {
s = &Snippet{ s = &Snippet{
id.Pos().Line, id.Pos().Line,
fmt.Sprintf(`could not generate a snippet for <span class="highlight">%s</span>`, id.Value), fmt.Sprintf(`could not generate a snippet for <span class="highlight">%s</span>`, id.Name()),
} }
} }
return return
......
...@@ -27,6 +27,7 @@ var ( ...@@ -27,6 +27,7 @@ var (
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')") rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
// debugging support // debugging support
checks = flag.Bool("checks", false, "do semantic checks")
comments = flag.Bool("comments", true, "print comments") comments = flag.Bool("comments", true, "print comments")
trace = flag.Bool("trace", false, "print parse trace") trace = flag.Bool("trace", false, "print parse trace")
...@@ -63,6 +64,9 @@ func usage() { ...@@ -63,6 +64,9 @@ func usage() {
func initParserMode() { func initParserMode() {
parserMode = uint(0) parserMode = uint(0)
if *checks {
parserMode |= parser.CheckSemantics
}
if *comments { if *comments {
parserMode |= parser.ParseComments parserMode |= parser.ParseComments
} }
......
...@@ -109,7 +109,7 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool { ...@@ -109,7 +109,7 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
// times in the pattern, it must match the same expression // times in the pattern, it must match the same expression
// each time. // each time.
if m != nil && pattern.Type() == identType { if m != nil && pattern.Type() == identType {
name := pattern.Interface().(*ast.Ident).Value name := pattern.Interface().(*ast.Ident).Name()
if isWildcard(name) { if isWildcard(name) {
if old, ok := m[name]; ok { if old, ok := m[name]; ok {
return match(nil, old, val) return match(nil, old, val)
...@@ -184,7 +184,7 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) ...@@ -184,7 +184,7 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value)
// Wildcard gets replaced with map value. // Wildcard gets replaced with map value.
if m != nil && pattern.Type() == identType { if m != nil && pattern.Type() == identType {
name := pattern.Interface().(*ast.Ident).Value name := pattern.Interface().(*ast.Ident).Name()
if isWildcard(name) { if isWildcard(name) {
if old, ok := m[name]; ok { if old, ok := m[name]; ok {
return subst(nil, old, nil) return subst(nil, old, nil)
......
...@@ -578,7 +578,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr { ...@@ -578,7 +578,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
} }
case *ast.Ident: case *ast.Ident:
return ei.compileIdent(a.block, a.constant, callCtx, x.Value) return ei.compileIdent(a.block, a.constant, callCtx, x.Name())
case *ast.IndexExpr: case *ast.IndexExpr:
l, r := a.compile(x.X, false), a.compile(x.Index, false) l, r := a.compile(x.X, false), a.compile(x.Index, false)
...@@ -612,7 +612,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr { ...@@ -612,7 +612,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
if v == nil { if v == nil {
return nil return nil
} }
return ei.compileSelectorExpr(v, x.Sel.Value) return ei.compileSelectorExpr(v, x.Sel.Name())
case *ast.StarExpr: case *ast.StarExpr:
// We pass down our call context because this could be // We pass down our call context because this could be
......
...@@ -210,15 +210,15 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) { ...@@ -210,15 +210,15 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) {
*/ */
func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable { func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
v, prev := a.block.DefineVar(ident.Value, ident.Pos(), t) v, prev := a.block.DefineVar(ident.Name(), ident.Pos(), t)
if prev != nil { if prev != nil {
// TODO(austin) It's silly that we have to capture // TODO(austin) It's silly that we have to capture
// Pos() in a variable. // Pos() in a variable.
pos := prev.Pos() pos := prev.Pos()
if pos.IsValid() { if pos.IsValid() {
a.diagAt(ident, "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Value, &pos) a.diagAt(ident, "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Name(), &pos)
} else { } else {
a.diagAt(ident, "variable %s redeclared in this block", ident.Value) a.diagAt(ident, "variable %s redeclared in this block", ident.Name())
} }
return nil return nil
} }
...@@ -381,13 +381,13 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) { ...@@ -381,13 +381,13 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) {
} }
// Declare and initialize v before compiling func // Declare and initialize v before compiling func
// so that body can refer to itself. // so that body can refer to itself.
c, prev := a.block.DefineConst(d.Name.Value, a.pos, decl.Type, decl.Type.Zero()) c, prev := a.block.DefineConst(d.Name.Name(), a.pos, decl.Type, decl.Type.Zero())
if prev != nil { if prev != nil {
pos := prev.Pos() pos := prev.Pos()
if pos.IsValid() { if pos.IsValid() {
a.diagAt(d.Name, "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Value, &pos) a.diagAt(d.Name, "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Name(), &pos)
} else { } else {
a.diagAt(d.Name, "identifier %s redeclared in this block", d.Name.Value) a.diagAt(d.Name, "identifier %s redeclared in this block", d.Name.Name())
} }
} }
fn := a.compileFunc(a.block, decl, d.Body) fn := a.compileFunc(a.block, decl, d.Body)
...@@ -416,14 +416,14 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) { ...@@ -416,14 +416,14 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) {
func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) { func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) {
// Define label // Define label
l, ok := a.labels[s.Label.Value] l, ok := a.labels[s.Label.Name()]
if ok { if ok {
if l.resolved.IsValid() { if l.resolved.IsValid() {
a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Value, &l.resolved) a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Name(), &l.resolved)
} }
} else { } else {
pc := badPC pc := badPC
l = &label{name: s.Label.Value, gotoPC: &pc} l = &label{name: s.Label.Name(), gotoPC: &pc}
a.labels[l.name] = l a.labels[l.name] = l
} }
l.desc = "regular label" l.desc = "regular label"
...@@ -562,7 +562,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, ...@@ -562,7 +562,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
} }
// Is this simply an assignment? // Is this simply an assignment?
if _, ok := a.block.defs[ident.Value]; ok { if _, ok := a.block.defs[ident.Name()]; ok {
ident = nil ident = nil
break break
} }
...@@ -861,7 +861,7 @@ func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, ...@@ -861,7 +861,7 @@ func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool,
if name == nil && pred(l) { if name == nil && pred(l) {
return l return l
} }
if name != nil && l.name == name.Value { if name != nil && l.name == name.Name() {
if !pred(l) { if !pred(l) {
a.diag("cannot %s to %s %s", errOp, l.desc, l.name) a.diag("cannot %s to %s %s", errOp, l.desc, l.name)
return nil return nil
...@@ -872,7 +872,7 @@ func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, ...@@ -872,7 +872,7 @@ func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool,
if name == nil { if name == nil {
a.diag("%s outside %s", errOp, errCtx) a.diag("%s outside %s", errOp, errCtx)
} else { } else {
a.diag("%s label %s not defined", errOp, name.Value) a.diag("%s label %s not defined", errOp, name.Name())
} }
return nil return nil
} }
...@@ -896,10 +896,10 @@ func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) { ...@@ -896,10 +896,10 @@ func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
pc = l.continuePC pc = l.continuePC
case token.GOTO: case token.GOTO:
l, ok := a.labels[s.Label.Value] l, ok := a.labels[s.Label.Name()]
if !ok { if !ok {
pc := badPC pc := badPC
l = &label{name: s.Label.Value, desc: "unresolved label", gotoPC: &pc, used: s.Pos()} l = &label{name: s.Label.Name(), desc: "unresolved label", gotoPC: &pc, used: s.Pos()}
a.labels[l.name] = l a.labels[l.name] = l
} }
...@@ -1235,14 +1235,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f ...@@ -1235,14 +1235,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
defer bodyScope.exit() defer bodyScope.exit()
for i, t := range decl.Type.In { for i, t := range decl.Type.In {
if decl.InNames[i] != nil { if decl.InNames[i] != nil {
bodyScope.DefineVar(decl.InNames[i].Value, decl.InNames[i].Pos(), t) bodyScope.DefineVar(decl.InNames[i].Name(), decl.InNames[i].Pos(), t)
} else { } else {
bodyScope.DefineTemp(t) bodyScope.DefineTemp(t)
} }
} }
for i, t := range decl.Type.Out { for i, t := range decl.Type.Out {
if decl.OutNames[i] != nil { if decl.OutNames[i] != nil {
bodyScope.DefineVar(decl.OutNames[i].Value, decl.OutNames[i].Pos(), t) bodyScope.DefineVar(decl.OutNames[i].Name(), decl.OutNames[i].Pos(), t)
} else { } else {
bodyScope.DefineTemp(t) bodyScope.DefineTemp(t)
} }
......
...@@ -764,7 +764,7 @@ func typeListString(ts []Type, ns []*ast.Ident) string { ...@@ -764,7 +764,7 @@ func typeListString(ts []Type, ns []*ast.Ident) string {
s += ", " s += ", "
} }
if ns != nil && ns[i] != nil { if ns != nil && ns[i] != nil {
s += ns[i].Value + " " s += ns[i].Name() + " "
} }
if t == nil { if t == nil {
// Some places use nil types to represent errors // Some places use nil types to represent errors
...@@ -808,7 +808,7 @@ type FuncDecl struct { ...@@ -808,7 +808,7 @@ type FuncDecl struct {
func (t *FuncDecl) String() string { func (t *FuncDecl) String() string {
s := "func" s := "func"
if t.Name != nil { if t.Name != nil {
s += " " + t.Name.Value s += " " + t.Name.Name()
} }
s += funcTypeString(t.Type, t.InNames, t.OutNames) s += funcTypeString(t.Type, t.InNames, t.OutNames)
return s return s
......
...@@ -26,17 +26,17 @@ type typeCompiler struct { ...@@ -26,17 +26,17 @@ type typeCompiler struct {
} }
func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type { func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
_, _, def := a.block.Lookup(x.Value) _, _, def := a.block.Lookup(x.Name())
if def == nil { if def == nil {
a.diagAt(x, "%s: undefined", x.Value) a.diagAt(x, "%s: undefined", x.Name())
return nil return nil
} }
switch def := def.(type) { switch def := def.(type) {
case *Constant: case *Constant:
a.diagAt(x, "constant %v used as type", x.Value) a.diagAt(x, "constant %v used as type", x.Name())
return nil return nil
case *Variable: case *Variable:
a.diagAt(x, "variable %v used as type", x.Value) a.diagAt(x, "variable %v used as type", x.Name())
return nil return nil
case *NamedType: case *NamedType:
if !allowRec && def.incomplete { if !allowRec && def.incomplete {
...@@ -51,7 +51,7 @@ func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type { ...@@ -51,7 +51,7 @@ func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
case Type: case Type:
return def return def
} }
log.Crashf("name %s has unknown type %T", x.Value, def) log.Crashf("name %s has unknown type %T", x.Name(), def)
return nil return nil
} }
...@@ -147,7 +147,7 @@ func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type ...@@ -147,7 +147,7 @@ func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type
// Compute field name and check anonymous fields // Compute field name and check anonymous fields
var name string var name string
if names[i] != nil { if names[i] != nil {
name = names[i].Value name = names[i].Name()
} else { } else {
if ts[i] == nil { if ts[i] == nil {
continue continue
...@@ -247,7 +247,7 @@ func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) ...@@ -247,7 +247,7 @@ func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool)
} }
if names[i] != nil { if names[i] != nil {
name := names[i].Value name := names[i].Name()
methods[nm].Name = name methods[nm].Name = name
methods[nm].Type = ts[i].(*FuncType) methods[nm].Type = ts[i].(*FuncType)
nm++ nm++
...@@ -380,7 +380,7 @@ func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool { ...@@ -380,7 +380,7 @@ func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
for _, spec := range decl.Specs { for _, spec := range decl.Specs {
spec := spec.(*ast.TypeSpec) spec := spec.(*ast.TypeSpec)
// Create incomplete type for this type // Create incomplete type for this type
nt := b.DefineType(spec.Name.Value, spec.Name.Pos(), nil) nt := b.DefineType(spec.Name.Name(), spec.Name.Pos(), nil)
if nt != nil { if nt != nil {
nt.(*NamedType).incomplete = true nt.(*NamedType).incomplete = true
} }
......
...@@ -148,8 +148,8 @@ func ParsePkgFile(pkgname, filename string, mode uint) (*ast.File, os.Error) { ...@@ -148,8 +148,8 @@ func ParsePkgFile(pkgname, filename string, mode uint) (*ast.File, os.Error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if prog.Name.Value != pkgname { if prog.Name.Name() != pkgname {
return nil, os.NewError(fmt.Sprintf("multiple packages found: %s, %s", prog.Name.Value, pkgname)) return nil, os.NewError(fmt.Sprintf("multiple packages found: %s, %s", prog.Name.Name(), pkgname))
} }
if mode == PackageClauseOnly { if mode == PackageClauseOnly {
return prog, nil return prog, nil
...@@ -189,7 +189,7 @@ func ParsePackage(path string, filter func(*os.Dir) bool, mode uint) (*ast.Packa ...@@ -189,7 +189,7 @@ func ParsePackage(path string, filter func(*os.Dir) bool, mode uint) (*ast.Packa
} }
files[entry.Name] = src files[entry.Name] = src
if name == "" { if name == "" {
name = src.Name.Value name = src.Name.Name()
} }
} }
} }
......
...@@ -267,44 +267,18 @@ func (p *parser) expect(tok token.Token) token.Position { ...@@ -267,44 +267,18 @@ func (p *parser) expect(tok token.Token) token.Position {
} }
// ----------------------------------------------------------------------------
// Scope support
func openScope(p *parser) *parser {
p.topScope = ast.NewScope(p.topScope)
return p
}
// Usage pattern: defer close(openScope(p));
func close(p *parser) { p.topScope = p.topScope.Outer }
func (p *parser) declare(ident *ast.Ident) {
if !p.topScope.Declare(ident) {
p.Error(p.pos, "'"+ident.Value+"' declared already")
}
}
func (p *parser) declareList(idents []*ast.Ident) {
for _, ident := range idents {
p.declare(ident)
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Common productions // Common productions
func (p *parser) parseIdent() *ast.Ident { func (p *parser) parseIdent() *ast.Ident {
obj := ast.NewObj(ast.Err, p.pos, "")
if p.tok == token.IDENT { if p.tok == token.IDENT {
x := &ast.Ident{p.pos, string(p.lit)} obj.Name = string(p.lit)
p.next() p.next()
return x } else {
p.expect(token.IDENT) // use expect() error handling
} }
p.expect(token.IDENT) // use expect() error handling return &ast.Ident{obj.Pos, obj}
return &ast.Ident{p.pos, ""}
} }
...@@ -424,7 +398,7 @@ func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident { ...@@ -424,7 +398,7 @@ func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident {
if !isIdent { if !isIdent {
pos := list.At(i).(ast.Expr).Pos() pos := list.At(i).(ast.Expr).Pos()
p.errorExpected(pos, "identifier") p.errorExpected(pos, "identifier")
idents[i] = &ast.Ident{pos, ""} idents[i] = &ast.Ident{pos, ast.NewObj(ast.Err, pos, "")}
} }
idents[i] = ident idents[i] = ident
} }
...@@ -835,8 +809,6 @@ func (p *parser) parseBlockStmt(idents []*ast.Ident) *ast.BlockStmt { ...@@ -835,8 +809,6 @@ func (p *parser) parseBlockStmt(idents []*ast.Ident) *ast.BlockStmt {
defer un(trace(p, "BlockStmt")) defer un(trace(p, "BlockStmt"))
} }
defer close(openScope(p))
lbrace := p.expect(token.LBRACE) lbrace := p.expect(token.LBRACE)
list := p.parseStmtList() list := p.parseStmtList()
rbrace := p.expect(token.RBRACE) rbrace := p.expect(token.RBRACE)
...@@ -1421,9 +1393,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt { ...@@ -1421,9 +1393,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
defer un(trace(p, "IfStmt")) defer un(trace(p, "IfStmt"))
} }
// IfStmt block
defer close(openScope(p))
pos := p.expect(token.IF) pos := p.expect(token.IF)
s1, s2, _ := p.parseControlClause(false) s1, s2, _ := p.parseControlClause(false)
body := p.parseBlockStmt(nil) body := p.parseBlockStmt(nil)
...@@ -1442,9 +1411,6 @@ func (p *parser) parseCaseClause() *ast.CaseClause { ...@@ -1442,9 +1411,6 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
defer un(trace(p, "CaseClause")) defer un(trace(p, "CaseClause"))
} }
// CaseClause block
defer close(openScope(p))
// SwitchCase // SwitchCase
pos := p.pos pos := p.pos
var x []ast.Expr var x []ast.Expr
...@@ -1489,9 +1455,6 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause { ...@@ -1489,9 +1455,6 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
defer un(trace(p, "TypeCaseClause")) defer un(trace(p, "TypeCaseClause"))
} }
// TypeCaseClause block
defer close(openScope(p))
// TypeSwitchCase // TypeSwitchCase
pos := p.pos pos := p.pos
var types []ast.Expr var types []ast.Expr
...@@ -1528,9 +1491,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt { ...@@ -1528,9 +1491,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
defer un(trace(p, "SwitchStmt")) defer un(trace(p, "SwitchStmt"))
} }
// SwitchStmt block
defer close(openScope(p))
pos := p.expect(token.SWITCH) pos := p.expect(token.SWITCH)
s1, s2, _ := p.parseControlClause(false) s1, s2, _ := p.parseControlClause(false)
...@@ -1565,9 +1525,6 @@ func (p *parser) parseCommClause() *ast.CommClause { ...@@ -1565,9 +1525,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
defer un(trace(p, "CommClause")) defer un(trace(p, "CommClause"))
} }
// CommClause block
defer close(openScope(p))
// CommCase // CommCase
pos := p.pos pos := p.pos
var tok token.Token var tok token.Token
...@@ -1628,9 +1585,6 @@ func (p *parser) parseForStmt() ast.Stmt { ...@@ -1628,9 +1585,6 @@ func (p *parser) parseForStmt() ast.Stmt {
defer un(trace(p, "ForStmt")) defer un(trace(p, "ForStmt"))
} }
// ForStmt block
defer close(openScope(p))
pos := p.expect(token.FOR) pos := p.expect(token.FOR)
s1, s2, s3 := p.parseControlClause(true) s1, s2, s3 := p.parseControlClause(true)
body := p.parseBlockStmt(nil) body := p.parseBlockStmt(nil)
...@@ -1745,7 +1699,7 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.S ...@@ -1745,7 +1699,7 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.S
var ident *ast.Ident var ident *ast.Ident
if p.tok == token.PERIOD { if p.tok == token.PERIOD {
ident = &ast.Ident{p.pos, "."} ident = &ast.Ident{p.pos, ast.NewObj(ast.Err, p.pos, ".")}
p.next() p.next()
} else if p.tok == token.IDENT { } else if p.tok == token.IDENT {
ident = p.parseIdent() ident = p.parseIdent()
...@@ -1974,9 +1928,6 @@ func (p *parser) parseFile() *ast.File { ...@@ -1974,9 +1928,6 @@ func (p *parser) parseFile() *ast.File {
defer un(trace(p, "File")) defer un(trace(p, "File"))
} }
// file block
defer close(openScope(p))
// package clause // package clause
doc := p.leadComment doc := p.leadComment
pos := p.expect(token.PACKAGE) pos := p.expect(token.PACKAGE)
......
...@@ -117,8 +117,8 @@ type ( ...@@ -117,8 +117,8 @@ type (
// An Ident node represents an identifier. // An Ident node represents an identifier.
Ident struct { Ident struct {
token.Position // identifier position token.Position // identifier position
Value string // identifier string (e.g. foobar) Obj *Object // denoted object
} }
// An Ellipsis node stands for the "..." type in a // An Ellipsis node stands for the "..." type in a
...@@ -139,6 +139,8 @@ type ( ...@@ -139,6 +139,8 @@ type (
// A single string literal (common case) is represented by a BasicLit // A single string literal (common case) is represented by a BasicLit
// node; StringList nodes are used only if there are two or more string // node; StringList nodes are used only if there are two or more string
// literals in a sequence. // literals in a sequence.
// TODO(gri) Deprecated. StringLists are only created by exp/parser;
// Remove when exp/parser is removed.
// //
StringList struct { StringList struct {
Strings []*BasicLit // list of strings, len(Strings) > 1 Strings []*BasicLit // list of strings, len(Strings) > 1
...@@ -346,6 +348,16 @@ func (x *MapType) exprNode() {} ...@@ -346,6 +348,16 @@ func (x *MapType) exprNode() {}
func (x *ChanType) exprNode() {} func (x *ChanType) exprNode() {}
// ----------------------------------------------------------------------------
// Convenience functions for Idents
// NewIdent creates a new Ident without position and minimal object
// information. Useful for ASTs generated by code other than the Go
// parser.
//
func NewIdent(name string) *Ident { return &Ident{noPos, NewObj(Err, noPos, name)} }
// IsExported returns whether name is an exported Go symbol // IsExported returns whether name is an exported Go symbol
// (i.e., whether it begins with an uppercase letter). // (i.e., whether it begins with an uppercase letter).
func IsExported(name string) bool { func IsExported(name string) bool {
...@@ -353,13 +365,19 @@ func IsExported(name string) bool { ...@@ -353,13 +365,19 @@ func IsExported(name string) bool {
return unicode.IsUpper(ch) return unicode.IsUpper(ch)
} }
// IsExported returns whether name is an exported Go symbol
// IsExported returns whether id is an exported Go symbol
// (i.e., whether it begins with an uppercase letter). // (i.e., whether it begins with an uppercase letter).
func (name *Ident) IsExported() bool { return IsExported(name.Value) } func (id *Ident) IsExported() bool { return id.Obj.IsExported() }
// Name returns an identifier's name.
func (id *Ident) Name() string { return id.Obj.Name }
func (name *Ident) String() string { func (id *Ident) String() string {
if name != nil { if id != nil && id.Obj != nil {
return name.Value return id.Obj.Name
} }
return "<nil>" return "<nil>"
} }
......
...@@ -249,5 +249,5 @@ func MergePackageFiles(pkg *Package) *File { ...@@ -249,5 +249,5 @@ func MergePackageFiles(pkg *Package) *File {
// TODO(gri) Should collect comments as well. For that the comment // TODO(gri) Should collect comments as well. For that the comment
// list should be changed back into a []*CommentGroup, // list should be changed back into a []*CommentGroup,
// otherwise need to modify the existing linked list. // otherwise need to modify the existing linked list.
return &File{doc, noPos, &Ident{noPos, pkg.Name}, decls, nil} return &File{doc, noPos, NewIdent(pkg.Name), decls, nil}
} }
...@@ -4,89 +4,78 @@ ...@@ -4,89 +4,78 @@
package ast package ast
// A Scope maintains the set of identifiers visible import "go/token"
// in the scope and a link to the immediately surrounding
// (outer) scope. type ObjKind int
// The list of possible Object kinds.
const (
Err ObjKind = iota // object kind unknown (forward reference or error)
Pkg // package
Con // constant
Typ // type
Var // variable
Fun // function or method
)
// An Object describes a language entity such as a package,
// constant, type, variable, or function (incl. methods).
// //
// NOTE: WORK IN PROGRESS type Object struct {
Kind ObjKind
Pos token.Position // declaration position
Name string // declared name
Scope *Scope // scope in which the Object is declared
}
func NewObj(kind ObjKind, pos token.Position, name string) *Object {
return &Object{kind, pos, name, nil}
}
// IsExported returns whether obj is exported.
func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
// A Scope maintains the set of named language entities visible
// in the scope and a link to the immediately surrounding (outer)
// scope.
// //
type Scope struct { type Scope struct {
Outer *Scope Outer *Scope
Names map[string]*Ident Objects map[string]*Object
} }
// NewScope creates a new scope nested in the outer scope. // NewScope creates a new scope nested in the outer scope.
func NewScope(outer *Scope) *Scope { return &Scope{outer, make(map[string]*Ident)} } func NewScope(outer *Scope) *Scope { return &Scope{outer, make(map[string]*Object)} }
// Declare inserts an identifier into the scope s. If the // Declare attempts to insert a named object into the scope s.
// declaration succeeds, the result is true, if the identifier // If the scope does not contain an object with that name yet,
// exists already in the scope, the result is false. // Declare inserts the object, and the result is true. Otherwise,
// // the scope remains unchanged and the result is false.
func (s *Scope) Declare(ident *Ident) bool { func (s *Scope) Declare(obj *Object) bool {
if _, found := s.Names[ident.Value]; found { if obj.Name != "_" {
return false if _, found := s.Objects[obj.Name]; found {
return false
}
s.Objects[obj.Name] = obj
} }
s.Names[ident.Value] = ident
return true return true
} }
// Lookup looks up an identifier in the current scope chain. // Lookup looks up an object in the current scope chain.
// If the identifier is found, it is returned; otherwise the // The result is nil if the object is not found.
// result is nil.
// //
func (s *Scope) Lookup(name string) *Ident { func (s *Scope) Lookup(name string) *Object {
for ; s != nil; s = s.Outer { for ; s != nil; s = s.Outer {
if ident, found := s.Names[name]; found { if obj, found := s.Objects[name]; found {
return ident return obj
} }
} }
return nil return nil
} }
// TODO(gri) Uncomment once this code is needed.
/*
var Universe = Scope {
Names: map[string]*Ident {
// basic types
"bool": nil,
"byte": nil,
"int8": nil,
"int16": nil,
"int32": nil,
"int64": nil,
"uint8": nil,
"uint16": nil,
"uint32": nil,
"uint64": nil,
"float32": nil,
"float64": nil,
"string": nil,
// convenience types
"int": nil,
"uint": nil,
"uintptr": nil,
"float": nil,
// constants
"false": nil,
"true": nil,
"iota": nil,
"nil": nil,
// functions
"cap": nil,
"len": nil,
"new": nil,
"make": nil,
"panic": nil,
"panicln": nil,
"print": nil,
"println": nil,
}
}
*/
\ No newline at end of file
...@@ -55,7 +55,7 @@ func (doc *docReader) init(pkgName string) { ...@@ -55,7 +55,7 @@ func (doc *docReader) init(pkgName string) {
func (doc *docReader) addType(decl *ast.GenDecl) { func (doc *docReader) addType(decl *ast.GenDecl) {
spec := decl.Specs[0].(*ast.TypeSpec) spec := decl.Specs[0].(*ast.TypeSpec)
typ := doc.lookupTypeDoc(spec.Name.Value) typ := doc.lookupTypeDoc(spec.Name.Name())
// typ should always be != nil since declared types // typ should always be != nil since declared types
// are always named - be conservative and check // are always named - be conservative and check
if typ != nil { if typ != nil {
...@@ -86,7 +86,7 @@ func baseTypeName(typ ast.Expr) string { ...@@ -86,7 +86,7 @@ func baseTypeName(typ ast.Expr) string {
// if the type is not exported, the effect to // if the type is not exported, the effect to
// a client is as if there were no type name // a client is as if there were no type name
if t.IsExported() { if t.IsExported() {
return string(t.Value) return string(t.Name())
} }
case *ast.StarExpr: case *ast.StarExpr:
return baseTypeName(t.X) return baseTypeName(t.X)
...@@ -148,7 +148,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) { ...@@ -148,7 +148,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
func (doc *docReader) addFunc(fun *ast.FuncDecl) { func (doc *docReader) addFunc(fun *ast.FuncDecl) {
name := fun.Name.Value name := fun.Name.Name()
// determine if it should be associated with a type // determine if it should be associated with a type
if fun.Recv != nil { if fun.Recv != nil {
...@@ -291,7 +291,7 @@ func (doc *docReader) addFile(src *ast.File) { ...@@ -291,7 +291,7 @@ func (doc *docReader) addFile(src *ast.File) {
func NewFileDoc(file *ast.File) *PackageDoc { func NewFileDoc(file *ast.File) *PackageDoc {
var r docReader var r docReader
r.init(file.Name.Value) r.init(file.Name.Name())
r.addFile(file) r.addFile(file)
return r.newDoc("", "", nil) return r.newDoc("", "", nil)
} }
...@@ -336,9 +336,9 @@ func declName(d *ast.GenDecl) string { ...@@ -336,9 +336,9 @@ func declName(d *ast.GenDecl) string {
switch v := d.Specs[0].(type) { switch v := d.Specs[0].(type) {
case *ast.ValueSpec: case *ast.ValueSpec:
return v.Names[0].Value return v.Names[0].Name()
case *ast.TypeSpec: case *ast.TypeSpec:
return v.Name.Value return v.Name.Name()
} }
return "" return ""
...@@ -400,7 +400,7 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc { ...@@ -400,7 +400,7 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
if f.Recv != nil { if f.Recv != nil {
doc.Recv = f.Recv.Type doc.Recv = f.Recv.Type
} }
doc.Name = f.Name.Value doc.Name = f.Name.Name()
doc.Decl = f doc.Decl = f
d[i] = doc d[i] = doc
i++ i++
...@@ -433,7 +433,7 @@ func (p sortTypeDoc) Less(i, j int) bool { ...@@ -433,7 +433,7 @@ func (p sortTypeDoc) Less(i, j int) bool {
// sort by name // sort by name
// pull blocks (name = "") up to top // pull blocks (name = "") up to top
// in original order // in original order
if ni, nj := p[i].Type.Name.Value, p[j].Type.Name.Value; ni != nj { if ni, nj := p[i].Type.Name.Name(), p[j].Type.Name.Name(); ni != nj {
return ni < nj return ni < nj
} }
return p[i].order < p[j].order return p[i].order < p[j].order
...@@ -581,12 +581,12 @@ func matchDecl(d *ast.GenDecl, names []string) bool { ...@@ -581,12 +581,12 @@ func matchDecl(d *ast.GenDecl, names []string) bool {
switch v := d.(type) { switch v := d.(type) {
case *ast.ValueSpec: case *ast.ValueSpec:
for _, name := range v.Names { for _, name := range v.Names {
if match(name.Value, names) { if match(name.Name(), names) {
return true return true
} }
} }
case *ast.TypeSpec: case *ast.TypeSpec:
if match(v.Name.Value, names) { if match(v.Name.Name(), names) {
return true return true
} }
} }
......
...@@ -160,7 +160,7 @@ func ParseDir(path string, filter func(*os.Dir) bool, mode uint) (map[string]*as ...@@ -160,7 +160,7 @@ func ParseDir(path string, filter func(*os.Dir) bool, mode uint) (map[string]*as
if err != nil { if err != nil {
return pkgs, err return pkgs, err
} }
name := src.Name.Value name := src.Name.Name()
pkg, found := pkgs[name] pkg, found := pkgs[name]
if !found { if !found {
pkg = &ast.Package{name, path, make(map[string]*ast.File)} pkg = &ast.Package{name, path, make(map[string]*ast.File)}
......
...@@ -30,6 +30,7 @@ const ( ...@@ -30,6 +30,7 @@ const (
PackageClauseOnly uint = 1 << iota // parsing stops after package clause PackageClauseOnly uint = 1 << iota // parsing stops after package clause
ImportsOnly // parsing stops after import declarations ImportsOnly // parsing stops after import declarations
ParseComments // parse comments and add them to AST ParseComments // parse comments and add them to AST
CheckSemantics // do semantic checks (only declarations for now)
Trace // print a trace of parsed productions Trace // print a trace of parsed productions
) )
...@@ -41,6 +42,7 @@ type parser struct { ...@@ -41,6 +42,7 @@ type parser struct {
// Tracing/debugging // Tracing/debugging
mode uint // parsing mode mode uint // parsing mode
check bool // == (mode & CheckSemantics != 0)
trace bool // == (mode & Trace != 0) trace bool // == (mode & Trace != 0)
indent uint // indentation used for tracing output indent uint // indentation used for tracing output
...@@ -78,7 +80,8 @@ func scannerMode(mode uint) uint { ...@@ -78,7 +80,8 @@ func scannerMode(mode uint) uint {
func (p *parser) init(filename string, src []byte, mode uint) { func (p *parser) init(filename string, src []byte, mode uint) {
p.scanner.Init(filename, src, p, scannerMode(mode)) p.scanner.Init(filename, src, p, scannerMode(mode))
p.mode = mode p.mode = mode
p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently) p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
p.check = mode&CheckSemantics != 0 // for convenience (p.check is used frequently)
p.next() p.next()
} }
...@@ -270,54 +273,64 @@ func (p *parser) expectSemi() { ...@@ -270,54 +273,64 @@ func (p *parser) expectSemi() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Scope support // Scope support
// Usage pattern: defer closeScope(openScope(p));
func openScope(p *parser) *parser { func openScope(p *parser) *parser {
p.topScope = ast.NewScope(p.topScope) p.topScope = ast.NewScope(p.topScope)
return p return p
} }
// Usage pattern: defer close(openScope(p)); func closeScope(p *parser) { p.topScope = p.topScope.Outer }
func close(p *parser) { p.topScope = p.topScope.Outer }
func (p *parser) declare(ident *ast.Ident) { func (p *parser) parseIdent(kind ast.ObjKind) *ast.Ident {
if !p.topScope.Declare(ident) { obj := ast.NewObj(ast.Err, p.pos, "")
p.Error(p.pos, "'"+ident.Value+"' declared already") if p.tok == token.IDENT {
} obj.Name = string(p.lit)
} p.next()
} else {
p.expect(token.IDENT) // use expect() error handling
func (p *parser) declareList(idents []*ast.Ident) {
for _, ident := range idents {
p.declare(ident)
} }
return &ast.Ident{obj.Pos, obj}
} }
// ---------------------------------------------------------------------------- // TODO(gri) Separate parsing from declaration since an identifier's
// Common productions // scope often starts only after the type has been seen.
func (p *parser) declIdent(kind ast.ObjKind) *ast.Ident {
func (p *parser) parseIdent() *ast.Ident { obj := ast.NewObj(kind, p.pos, "")
if p.tok == token.IDENT { if p.tok == token.IDENT {
x := &ast.Ident{p.pos, string(p.lit)} obj.Name = string(p.lit)
// TODO(gri) Consider reversing the conditionals below:
// always do the declaration but only report
// error if enabled (may be necessary to get
// search functionality in the presence of
// incorrect files).
if p.check && !p.topScope.Declare(obj) {
// TODO(gri) Declare could return already-declared
// object for a very good error message.
p.Error(obj.Pos, "'"+obj.Name+"' declared already")
}
p.next() p.next()
return x } else {
p.expect(token.IDENT) // use expect() error handling
} }
p.expect(token.IDENT) // use expect() error handling return &ast.Ident{obj.Pos, obj}
return &ast.Ident{p.pos, ""}
} }
func (p *parser) parseIdentList() []*ast.Ident { // TODO(gri) Separate parsing from declaration since an identifier's
// scope often starts only after the type has been seen.
func (p *parser) declIdentList(kind ast.ObjKind) []*ast.Ident {
if p.trace { if p.trace {
defer un(trace(p, "IdentList")) defer un(trace(p, "IdentList"))
} }
var list vector.Vector var list vector.Vector
list.Push(p.parseIdent()) list.Push(p.declIdent(kind))
for p.tok == token.COMMA { for p.tok == token.COMMA {
p.next() p.next()
list.Push(p.parseIdent()) list.Push(p.declIdent(kind))
} }
// convert vector // convert vector
...@@ -330,6 +343,27 @@ func (p *parser) parseIdentList() []*ast.Ident { ...@@ -330,6 +343,27 @@ func (p *parser) parseIdentList() []*ast.Ident {
} }
func (p *parser) findIdent() *ast.Ident {
pos := p.pos
name := ""
var obj *ast.Object
if p.tok == token.IDENT {
name = string(p.lit)
obj = p.topScope.Lookup(name)
p.next()
} else {
p.expect(token.IDENT) // use expect() error handling
}
if obj == nil {
obj = ast.NewObj(ast.Err, pos, name)
}
return &ast.Ident{obj.Pos, obj}
}
// ----------------------------------------------------------------------------
// Common productions
func makeExprList(list *vector.Vector) []ast.Expr { func makeExprList(list *vector.Vector) []ast.Expr {
exprs := make([]ast.Expr, len(*list)) exprs := make([]ast.Expr, len(*list))
for i, x := range *list { for i, x := range *list {
...@@ -380,11 +414,11 @@ func (p *parser) parseQualifiedIdent() ast.Expr { ...@@ -380,11 +414,11 @@ func (p *parser) parseQualifiedIdent() ast.Expr {
defer un(trace(p, "QualifiedIdent")) defer un(trace(p, "QualifiedIdent"))
} }
var x ast.Expr = p.parseIdent() var x ast.Expr = p.findIdent()
if p.tok == token.PERIOD { if p.tok == token.PERIOD {
// first identifier is a package identifier // first identifier is a package identifier
p.next() p.next()
sel := p.parseIdent() sel := p.findIdent()
x = &ast.SelectorExpr{x, sel} x = &ast.SelectorExpr{x, sel}
} }
return x return x
...@@ -427,7 +461,7 @@ func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident { ...@@ -427,7 +461,7 @@ func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident {
if !isIdent { if !isIdent {
pos := x.(ast.Expr).Pos() pos := x.(ast.Expr).Pos()
p.errorExpected(pos, "identifier") p.errorExpected(pos, "identifier")
idents[i] = &ast.Ident{pos, ""} idents[i] = &ast.Ident{pos, ast.NewObj(ast.Err, pos, "")}
} }
idents[i] = ident idents[i] = ident
} }
...@@ -585,7 +619,7 @@ func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field { ...@@ -585,7 +619,7 @@ func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field {
} }
for p.tok != token.RPAREN && p.tok != token.EOF { for p.tok != token.RPAREN && p.tok != token.EOF {
idents := p.parseIdentList() idents := p.declIdentList(ast.Var)
typ := p.parseParameterType(ellipsisOk) typ := p.parseParameterType(ellipsisOk)
list.Push(&ast.Field{nil, idents, typ, nil, nil}) list.Push(&ast.Field{nil, idents, typ, nil, nil})
if p.tok != token.COMMA { if p.tok != token.COMMA {
...@@ -619,9 +653,11 @@ func (p *parser) parseParameters(ellipsisOk bool) []*ast.Field { ...@@ -619,9 +653,11 @@ func (p *parser) parseParameters(ellipsisOk bool) []*ast.Field {
var params []*ast.Field var params []*ast.Field
p.expect(token.LPAREN) p.expect(token.LPAREN)
openScope(p)
if p.tok != token.RPAREN { if p.tok != token.RPAREN {
params = p.parseParameterList(ellipsisOk) params = p.parseParameterList(ellipsisOk)
} }
closeScope(p)
p.expect(token.RPAREN) p.expect(token.RPAREN)
return params return params
...@@ -823,7 +859,7 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt { ...@@ -823,7 +859,7 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
defer un(trace(p, "BlockStmt")) defer un(trace(p, "BlockStmt"))
} }
defer close(openScope(p)) defer closeScope(openScope(p))
lbrace := p.expect(token.LBRACE) lbrace := p.expect(token.LBRACE)
list := p.parseStmtList() list := p.parseStmtList()
...@@ -865,7 +901,7 @@ func (p *parser) parseOperand() ast.Expr { ...@@ -865,7 +901,7 @@ func (p *parser) parseOperand() ast.Expr {
switch p.tok { switch p.tok {
case token.IDENT: case token.IDENT:
return p.parseIdent() return p.findIdent()
case token.INT, token.FLOAT, token.CHAR, token.STRING: case token.INT, token.FLOAT, token.CHAR, token.STRING:
x := &ast.BasicLit{p.pos, p.tok, p.lit} x := &ast.BasicLit{p.pos, p.tok, p.lit}
...@@ -905,7 +941,7 @@ func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { ...@@ -905,7 +941,7 @@ func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
p.expect(token.PERIOD) p.expect(token.PERIOD)
if p.tok == token.IDENT { if p.tok == token.IDENT {
// selector // selector
sel := p.parseIdent() sel := p.findIdent()
return &ast.SelectorExpr{x, sel} return &ast.SelectorExpr{x, sel}
} }
...@@ -1325,7 +1361,7 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt { ...@@ -1325,7 +1361,7 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
s := &ast.BranchStmt{p.pos, tok, nil} s := &ast.BranchStmt{p.pos, tok, nil}
p.expect(tok) p.expect(tok)
if tok != token.FALLTHROUGH && p.tok == token.IDENT { if tok != token.FALLTHROUGH && p.tok == token.IDENT {
s.Label = p.parseIdent() s.Label = p.findIdent()
} }
p.expectSemi() p.expectSemi()
...@@ -1382,7 +1418,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt { ...@@ -1382,7 +1418,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
} }
// IfStmt block // IfStmt block
defer close(openScope(p)) defer closeScope(openScope(p))
pos := p.expect(token.IF) pos := p.expect(token.IF)
s1, s2, _ := p.parseControlClause(false) s1, s2, _ := p.parseControlClause(false)
...@@ -1405,7 +1441,7 @@ func (p *parser) parseCaseClause() *ast.CaseClause { ...@@ -1405,7 +1441,7 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
} }
// CaseClause block // CaseClause block
defer close(openScope(p)) defer closeScope(openScope(p))
// SwitchCase // SwitchCase
pos := p.pos pos := p.pos
...@@ -1446,7 +1482,7 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause { ...@@ -1446,7 +1482,7 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
} }
// TypeCaseClause block // TypeCaseClause block
defer close(openScope(p)) defer closeScope(openScope(p))
// TypeSwitchCase // TypeSwitchCase
pos := p.pos pos := p.pos
...@@ -1485,7 +1521,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt { ...@@ -1485,7 +1521,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
} }
// SwitchStmt block // SwitchStmt block
defer close(openScope(p)) defer closeScope(openScope(p))
pos := p.expect(token.SWITCH) pos := p.expect(token.SWITCH)
s1, s2, _ := p.parseControlClause(false) s1, s2, _ := p.parseControlClause(false)
...@@ -1522,7 +1558,7 @@ func (p *parser) parseCommClause() *ast.CommClause { ...@@ -1522,7 +1558,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
} }
// CommClause block // CommClause block
defer close(openScope(p)) defer closeScope(openScope(p))
// CommCase // CommCase
pos := p.pos pos := p.pos
...@@ -1585,7 +1621,7 @@ func (p *parser) parseForStmt() ast.Stmt { ...@@ -1585,7 +1621,7 @@ func (p *parser) parseForStmt() ast.Stmt {
} }
// ForStmt block // ForStmt block
defer close(openScope(p)) defer closeScope(openScope(p))
pos := p.expect(token.FOR) pos := p.expect(token.FOR)
s1, s2, s3 := p.parseControlClause(true) s1, s2, s3 := p.parseControlClause(true)
...@@ -1701,10 +1737,10 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec { ...@@ -1701,10 +1737,10 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
var ident *ast.Ident var ident *ast.Ident
if p.tok == token.PERIOD { if p.tok == token.PERIOD {
ident = &ast.Ident{p.pos, "."} ident = &ast.Ident{p.pos, ast.NewObj(ast.Pkg, p.pos, ".")}
p.next() p.next()
} else if p.tok == token.IDENT { } else if p.tok == token.IDENT {
ident = p.parseIdent() ident = p.declIdent(ast.Pkg)
} }
var path []*ast.BasicLit var path []*ast.BasicLit
...@@ -1726,7 +1762,7 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec { ...@@ -1726,7 +1762,7 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "ConstSpec")) defer un(trace(p, "ConstSpec"))
} }
idents := p.parseIdentList() idents := p.declIdentList(ast.Con)
typ := p.tryType() typ := p.tryType()
var values []ast.Expr var values []ast.Expr
if typ != nil || p.tok == token.ASSIGN { if typ != nil || p.tok == token.ASSIGN {
...@@ -1744,7 +1780,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec { ...@@ -1744,7 +1780,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "TypeSpec")) defer un(trace(p, "TypeSpec"))
} }
ident := p.parseIdent() ident := p.declIdent(ast.Typ)
typ := p.parseType() typ := p.parseType()
p.expectSemi() p.expectSemi()
...@@ -1757,7 +1793,7 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec { ...@@ -1757,7 +1793,7 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "VarSpec")) defer un(trace(p, "VarSpec"))
} }
idents := p.parseIdentList() idents := p.declIdentList(ast.Var)
typ := p.tryType() typ := p.tryType()
var values []ast.Expr var values []ast.Expr
if typ == nil || p.tok == token.ASSIGN { if typ == nil || p.tok == token.ASSIGN {
...@@ -1843,7 +1879,7 @@ func (p *parser) parseFunctionDecl() *ast.FuncDecl { ...@@ -1843,7 +1879,7 @@ func (p *parser) parseFunctionDecl() *ast.FuncDecl {
recv = p.parseReceiver() recv = p.parseReceiver()
} }
ident := p.parseIdent() ident := p.declIdent(ast.Fun)
params, results := p.parseSignature() params, results := p.parseSignature()
var body *ast.BlockStmt var body *ast.BlockStmt
...@@ -1915,15 +1951,15 @@ func (p *parser) parseFile() *ast.File { ...@@ -1915,15 +1951,15 @@ func (p *parser) parseFile() *ast.File {
defer un(trace(p, "File")) defer un(trace(p, "File"))
} }
// file block
defer close(openScope(p))
// package clause // package clause
doc := p.leadComment doc := p.leadComment
pos := p.expect(token.PACKAGE) pos := p.expect(token.PACKAGE)
ident := p.parseIdent() ident := p.parseIdent(ast.Pkg) // package name is in no scope
p.expectSemi() p.expectSemi()
// file block
defer closeScope(openScope(p))
var decls []ast.Decl var decls []ast.Decl
// Don't bother parsing the rest if we had errors already. // Don't bother parsing the rest if we had errors already.
......
...@@ -308,7 +308,7 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) { ...@@ -308,7 +308,7 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) {
if i > 0 { if i > 0 {
size += 2 // ", " size += 2 // ", "
} }
size += len(x.Value) size += len(x.Name())
if size >= maxSize { if size >= maxSize {
break break
} }
......
...@@ -734,7 +734,7 @@ func (p *printer) print(args ...) { ...@@ -734,7 +734,7 @@ func (p *printer) print(args ...) {
if p.Styler != nil { if p.Styler != nil {
data, tag = p.Styler.Ident(x) data, tag = p.Styler.Ident(x)
} else { } else {
data = strings.Bytes(x.Value) data = strings.Bytes(x.Name())
} }
case *ast.BasicLit: case *ast.BasicLit:
if p.Styler != nil { if p.Styler != nil {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment