Commit 1f9dfa29 authored by Robert Griesemer's avatar Robert Griesemer

go AST: First step towards augmenting AST with full type information.

- change ast.Ident back to contain the name and adjust all dependent code
- identifier object information will be added again through an optional
  typechecker phase (in the works).
- remove tracking of scopes in parser - it's easier to do this in a separate
  phase (in the works)
- in godoc, generate popup info table directly instead of through a formatter
  for simpler data flow (at the expense of a little bit more code)

Runs all tests.

As a result of this change, the currently shown popup information
(const, var, type, func, followed by identifier name) will not be
shown anymore temporarily.

R=rsc
CC=golang-dev
https://golang.org/cl/1994041
parent be97fa4c
...@@ -7,11 +7,8 @@ ...@@ -7,11 +7,8 @@
<script src="http://www.google.com/jsapi"></script> <script src="http://www.google.com/jsapi"></script>
<script src="/doc/popups.js"></script> <script src="/doc/popups.js"></script>
<script> <script>
var popup_data = [ {# IdList is HTML-escaped by godoc}
{.repeated section Data} var popup_data = {IdList}
'{@|popupInfo}',
{.end}
]
google.load("jquery", "1"); google.load("jquery", "1");
google.setOnLoadCallback(function() {.meta-left} google.setOnLoadCallback(function() {.meta-left}
...@@ -19,5 +16,5 @@ google.setOnLoadCallback(function() {.meta-left} ...@@ -19,5 +16,5 @@ google.setOnLoadCallback(function() {.meta-left}
{.meta-right}); {.meta-right});
</script> </script>
{# Source is HTML-escaped elsewhere} {# Source is HTML-escaped by godoc}
<pre>{Source}</pre> <pre>{Source}</pre>
...@@ -17,7 +17,7 @@ import ( ...@@ -17,7 +17,7 @@ import (
) )
func parse(name string, flags uint) *ast.File { func parse(name string, flags uint) *ast.File {
ast1, err := parser.ParseFile(name, nil, nil, flags) ast1, err := parser.ParseFile(name, nil, flags)
if err != nil { if err != nil {
if list, ok := err.(scanner.ErrorList); ok { if list, ok := err.(scanner.ErrorList); ok {
// If err is a scanner.ErrorList, its String will print just // If err is a scanner.ErrorList, its String will print just
...@@ -49,7 +49,7 @@ func (f *File) ReadGo(name string) { ...@@ -49,7 +49,7 @@ func (f *File) ReadGo(name string) {
ast1 := parse(name, parser.ParseComments) ast1 := parse(name, parser.ParseComments)
ast2 := parse(name, 0) ast2 := parse(name, 0)
f.Package = ast1.Name.Name() f.Package = ast1.Name.Name
f.Name = make(map[string]*Name) f.Name = make(map[string]*Name)
// In ast1, find the import "C" line and get any extra C preamble. // In ast1, find the import "C" line and get any extra C preamble.
...@@ -135,7 +135,7 @@ func (f *File) saveRef(x interface{}, context string) { ...@@ -135,7 +135,7 @@ func (f *File) saveRef(x interface{}, 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.Name() == "C" { if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
i := len(f.Ref) i := len(f.Ref)
if i >= cap(f.Ref) { if i >= cap(f.Ref) {
new := make([]*Ref, 2*i) new := make([]*Ref, 2*i)
...@@ -147,7 +147,7 @@ func (f *File) saveRef(x interface{}, context string) { ...@@ -147,7 +147,7 @@ func (f *File) saveRef(x interface{}, context string) {
if context == "as2" { if context == "as2" {
context = "expr" context = "expr"
} }
goname := sel.Sel.Name() goname := sel.Sel.Name
name := f.Name[goname] name := f.Name[goname]
if name == nil { if name == nil {
name = &Name{ name = &Name{
...@@ -212,7 +212,7 @@ func (f *File) saveExport2(x interface{}, context string) { ...@@ -212,7 +212,7 @@ func (f *File) saveExport2(x interface{}, context string) {
} }
for _, exp := range f.ExpFunc { for _, exp := range f.ExpFunc {
if exp.Func.Name.Name() == n.Name.Name() { if exp.Func.Name.Name == n.Name.Name {
exp.Func = n exp.Func = n
break break
} }
......
...@@ -145,7 +145,7 @@ func (p *Package) guessKinds(f *File) []*Name { ...@@ -145,7 +145,7 @@ func (p *Package) guessKinds(f *File) []*Name {
if _, err := strconv.Atoi(n.Define); err == nil { if _, err := strconv.Atoi(n.Define); err == nil {
ok = true ok = true
} else if n.Define[0] == '"' || n.Define[0] == '\'' { } else if n.Define[0] == '"' || n.Define[0] == '\'' {
_, err := parser.ParseExpr("", n.Define, nil) _, err := parser.ParseExpr("", n.Define)
if err == nil { if err == nil {
ok = true ok = true
} }
...@@ -801,7 +801,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -801,7 +801,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.Name()] = 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)
} }
...@@ -811,7 +811,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -811,7 +811,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.C = csyntax t.C = csyntax
} }
t.Align = align t.Align = align
c.typedef[name.Name()] = g c.typedef[name.Name] = g
} }
case *dwarf.TypedefType: case *dwarf.TypedefType:
...@@ -830,8 +830,8 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -830,8 +830,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.Name()]; !ok { if _, ok := c.typedef[name.Name]; !ok {
c.typedef[name.Name()] = sub.Go c.typedef[name.Name] = sub.Go
} }
case *dwarf.UcharType: case *dwarf.UcharType:
...@@ -875,7 +875,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -875,7 +875,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
} }
s = strings.Join(strings.Split(s, " ", -1), "") // strip spaces s = strings.Join(strings.Split(s, " ", -1), "") // strip spaces
name := c.Ident("_Ctype_" + s) name := c.Ident("_Ctype_" + s)
c.typedef[name.Name()] = t.Go c.typedef[name.Name] = t.Go
t.Go = name t.Go = name
} }
} }
......
...@@ -403,9 +403,9 @@ func (p *Package) writeExports(fgo2, fc *os.File) { ...@@ -403,9 +403,9 @@ func (p *Package) writeExports(fgo2, fc *os.File) {
fmt.Fprintf(fgcc, "}\n") fmt.Fprintf(fgcc, "}\n")
// Build the wrapper function compiled by 6c/8c // Build the wrapper function compiled by 6c/8c
goname := exp.Func.Name.Name() goname := exp.Func.Name.Name
if fn.Recv != nil { if fn.Recv != nil {
goname = "_cgoexpwrap_" + fn.Recv.List[0].Names[0].Name() + "_" + goname goname = "_cgoexpwrap_" + fn.Recv.List[0].Names[0].Name + "_" + goname
} }
fmt.Fprintf(fc, "#pragma dynexport _cgoexp_%s _cgoexp_%s\n", exp.ExpName, exp.ExpName) fmt.Fprintf(fc, "#pragma dynexport _cgoexp_%s _cgoexp_%s\n", exp.ExpName, exp.ExpName)
fmt.Fprintf(fc, "extern void ·%s();\n", goname) fmt.Fprintf(fc, "extern void ·%s();\n", goname)
...@@ -529,23 +529,23 @@ func (p *Package) cgoType(e ast.Expr) *Type { ...@@ -529,23 +529,23 @@ func (p *Package) cgoType(e ast.Expr) *Type {
if !ok { if !ok {
continue continue
} }
if ts.Name.Name() == t.Name() { if ts.Name.Name == t.Name {
return p.cgoType(ts.Type) return p.cgoType(ts.Type)
} }
} }
} }
for name, def := range p.Typedef { for name, def := range p.Typedef {
if name == t.Name() { if name == t.Name {
return p.cgoType(def) return p.cgoType(def)
} }
} }
if t.Name() == "uintptr" { if t.Name == "uintptr" {
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: "uintptr"} return &Type{Size: p.PtrSize, Align: p.PtrSize, C: "uintptr"}
} }
if t.Name() == "string" { if t.Name == "string" {
return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: "GoString"} return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: "GoString"}
} }
if r, ok := goTypes[t.Name()]; ok { if r, ok := goTypes[t.Name]; ok {
if r.Align > p.PtrSize { if r.Align > p.PtrSize {
r.Align = p.PtrSize r.Align = p.PtrSize
} }
......
...@@ -136,11 +136,11 @@ func isPkgDir(f *os.FileInfo) bool { ...@@ -136,11 +136,11 @@ func isPkgDir(f *os.FileInfo) bool {
func pkgName(filename string) string { func pkgName(filename string) string {
file, err := parser.ParseFile(filename, nil, nil, parser.PackageClauseOnly) file, err := parser.ParseFile(filename, nil, parser.PackageClauseOnly)
if err != nil || file == nil { if err != nil || file == nil {
return "" return ""
} }
return file.Name.Name() return file.Name.Name
} }
...@@ -246,12 +246,12 @@ func newDirTree(path, name string, depth, maxDepth int) *Directory { ...@@ -246,12 +246,12 @@ func newDirTree(path, name string, depth, maxDepth int) *Directory {
nfiles++ nfiles++
if synopses[0] == "" { if synopses[0] == "" {
// no "optimal" package synopsis yet; continue to collect synopses // no "optimal" package synopsis yet; continue to collect synopses
file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil, nil, file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil,
parser.ParseComments|parser.PackageClauseOnly) parser.ParseComments|parser.PackageClauseOnly)
if err == nil && file.Doc != nil { if err == nil && file.Doc != nil {
// prioritize documentation // prioritize documentation
i := -1 i := -1
switch file.Name.Name() { switch file.Name.Name {
case name: case name:
i = 0 // normal case: directory name matches package name i = 0 // normal case: directory name matches package name
case fakePkgName: case fakePkgName:
...@@ -453,7 +453,7 @@ type Styler struct { ...@@ -453,7 +453,7 @@ type Styler struct {
linetags bool linetags bool
highlight string highlight string
objmap map[*ast.Object]int objmap map[*ast.Object]int
count int idcount int
} }
...@@ -462,26 +462,72 @@ func newStyler(highlight string) *Styler { ...@@ -462,26 +462,72 @@ func newStyler(highlight string) *Styler {
} }
func (s *Styler) id(obj *ast.Object) int { // identId returns a number >= 0 identifying the *ast.Object
n, found := s.objmap[obj] // denoted by name. If no object is denoted, the result is < 0.
//
// TODO(gri): Consider making this a mapping from popup info
// (for that name) to id, instead of *ast.Object
// to id. If a lot of the popup info is the same
// (e.g. type information), this will reduce the
// size of the html generated.
func (s *Styler) identId(name *ast.Ident) int {
obj := name.Obj
if obj == nil || s.objmap == nil {
return -1
}
id, found := s.objmap[obj]
if !found { if !found {
n = s.count // first occurence
s.objmap[obj] = n id = s.idcount
s.count++ s.objmap[obj] = id
s.idcount++
} }
return n return id
} }
func (s *Styler) mapping() []*ast.Object { // writeObjInfo writes the popup info corresponding to obj to w.
if s.objmap == nil { // The text is HTML-escaped and does not contain single quotes.
return nil func writeObjInfo(w io.Writer, obj *ast.Object) {
// for now, show object kind and name; eventually
// do something more interesting (show declaration,
// for instance)
if obj.Kind != ast.Bad {
fmt.Fprintf(w, "%s ", obj.Kind)
} }
m := make([]*ast.Object, s.count) template.HTMLEscape(w, []byte(obj.Name))
for obj, i := range s.objmap { }
m[i] = obj
// idList returns a Javascript array (source) with identifier popup
// information: The i'th array entry is a single-quoted string with
// the popup information for an identifier x with s.identId(x) == i,
// for 0 <= i < s.idcount.
func (s *Styler) idList() []byte {
var buf bytes.Buffer
fmt.Fprintln(&buf, "[")
if s.idcount > 0 {
// invert objmap: create an array [id]obj from map[obj]id
a := make([]*ast.Object, s.idcount)
for obj, id := range s.objmap {
a[id] = obj
}
// for each id, print object info as single-quoted Javascript string
for id, obj := range a {
printIndex := false // enable for debugging (but longer html)
if printIndex {
fmt.Fprintf(&buf, "/* %4d */ ", id)
}
fmt.Fprint(&buf, "'")
writeObjInfo(&buf, obj)
fmt.Fprint(&buf, "',\n")
}
} }
return m
fmt.Fprintln(&buf, "]")
return buf.Bytes()
} }
...@@ -516,13 +562,13 @@ func (s *Styler) BasicLit(x *ast.BasicLit) (text []byte, tag printer.HTMLTag) { ...@@ -516,13 +562,13 @@ 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(name *ast.Ident) (text []byte, tag printer.HTMLTag) {
text = []byte(id.Name()) text = []byte(name.Name)
var str string var str string
if s.objmap != nil { if id := s.identId(name); id >= 0 {
str = fmt.Sprintf(` id="%d"`, s.id(id.Obj)) str = fmt.Sprintf(` id="%d"`, id)
} }
if s.highlight == id.Name() { if s.highlight == name.Name {
str += ` class="highlight"` str += ` class="highlight"`
} }
if str != "" { if str != "" {
...@@ -819,19 +865,6 @@ func localnameFmt(w io.Writer, x interface{}, format string) { ...@@ -819,19 +865,6 @@ func localnameFmt(w io.Writer, x interface{}, format string) {
} }
// Template formatter for "popupInfo" format.
func popupInfoFmt(w io.Writer, x interface{}, format string) {
obj := x.(*ast.Object)
// for now, show object kind and name; eventually
// do something more interesting (show declaration,
// for instance)
if obj.Kind != ast.Err {
fmt.Fprintf(w, "%s ", obj.Kind)
}
template.HTMLEscape(w, []byte(obj.Name))
}
var fmap = template.FormatterMap{ var fmap = template.FormatterMap{
"": textFmt, "": textFmt,
"html": htmlFmt, "html": htmlFmt,
...@@ -847,7 +880,6 @@ var fmap = template.FormatterMap{ ...@@ -847,7 +880,6 @@ var fmap = template.FormatterMap{
"time": timeFmt, "time": timeFmt,
"dir/": dirslashFmt, "dir/": dirslashFmt,
"localname": localnameFmt, "localname": localnameFmt,
"popupInfo": popupInfoFmt,
} }
...@@ -996,22 +1028,25 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte { ...@@ -996,22 +1028,25 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte {
func serveGoSource(c *http.Conn, r *http.Request, abspath, relpath string) { func serveGoSource(c *http.Conn, r *http.Request, abspath, relpath string) {
file, err := parser.ParseFile(abspath, nil, nil, parser.ParseComments) file, err := parser.ParseFile(abspath, nil, parser.ParseComments)
if err != nil { if err != nil {
log.Stderrf("parser.ParseFile: %s", err) log.Stderrf("parser.ParseFile: %s", err)
serveError(c, r, relpath, err) serveError(c, r, relpath, err)
return return
} }
// augment AST with types; ignore errors (partial type information ok)
// TODO(gri): invoke typechecker
var buf bytes.Buffer var buf bytes.Buffer
styler := newStyler(r.FormValue("h")) styler := newStyler(r.FormValue("h"))
writeNode(&buf, file, true, styler) writeNode(&buf, file, true, styler)
type SourceInfo struct { type SourceInfo struct {
IdList []byte
Source []byte Source []byte
Data []*ast.Object
} }
info := &SourceInfo{buf.Bytes(), styler.mapping()} info := &SourceInfo{styler.idList(), buf.Bytes()}
contents := applyTemplate(sourceHTML, "sourceHTML", info) contents := applyTemplate(sourceHTML, "sourceHTML", info)
servePage(c, "Source file "+relpath, "", "", contents) servePage(c, "Source file "+relpath, "", "", contents)
...@@ -1346,7 +1381,7 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) { ...@@ -1346,7 +1381,7 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
var title string var title string
switch { switch {
case info.PAst != nil: case info.PAst != nil:
title = "Package " + info.PAst.Name.Name() title = "Package " + info.PAst.Name.Name
case info.PDoc != nil: case info.PDoc != nil:
switch { switch {
case h.isPkg: case h.isPkg:
......
...@@ -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.Name()] lists, found := x.words[id.Name]
if !found { if !found {
lists = new(IndexResult) lists = new(IndexResult)
x.words[id.Name()] = lists x.words[id.Name] = lists
} }
if kind == Use || x.decl == nil { if kind == Use || x.decl == nil {
...@@ -596,13 +596,13 @@ func (x *Indexer) VisitFile(path string, f *os.FileInfo) { ...@@ -596,13 +596,13 @@ func (x *Indexer) VisitFile(path string, f *os.FileInfo) {
return return
} }
file, err := parser.ParseFile(path, nil, nil, parser.ParseComments) file, err := parser.ParseFile(path, nil, parser.ParseComments)
if err != nil { if err != nil {
return // ignore files with (parse) errors return // ignore files with (parse) errors
} }
dir, _ := pathutil.Split(path) dir, _ := pathutil.Split(path)
pak := Pak{dir, file.Name.Name()} pak := Pak{dir, file.Name.Name}
x.file = &File{path, pak} x.file = &File{path, pak}
ast.Walk(x, file) ast.Walk(x, file)
} }
......
...@@ -35,7 +35,7 @@ func (s *snippetStyler) LineTag(line int) (text []uint8, tag printer.HTMLTag) { ...@@ -35,7 +35,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 = []byte(id.Name()) text = []byte(id.Name)
if s.highlight == id { if s.highlight == id {
tag = printer.HTMLTag{"<span class=highlight>", "</span>"} tag = printer.HTMLTag{"<span class=highlight>", "</span>"}
} }
...@@ -114,7 +114,7 @@ func NewSnippet(decl ast.Decl, id *ast.Ident) (s *Snippet) { ...@@ -114,7 +114,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.Name()), fmt.Sprintf(`could not generate a snippet for <span class="highlight">%s</span>`, id.Name),
} }
} }
return return
......
...@@ -27,7 +27,6 @@ var ( ...@@ -27,7 +27,6 @@ var (
// debugging support // debugging support
comments = flag.Bool("comments", true, "print comments") comments = flag.Bool("comments", true, "print comments")
debug = flag.Bool("debug", false, "print debugging information")
trace = flag.Bool("trace", false, "print parse trace") trace = flag.Bool("trace", false, "print parse trace")
// layout control // layout control
...@@ -92,11 +91,7 @@ func processFile(f *os.File) os.Error { ...@@ -92,11 +91,7 @@ func processFile(f *os.File) os.Error {
return err return err
} }
var scope *ast.Scope file, err := parser.ParseFile(f.Name(), src, parserMode)
if *debug {
scope = ast.NewScope(nil)
}
file, err := parser.ParseFile(f.Name(), src, scope, parserMode)
if err != nil { if err != nil {
return err return err
......
...@@ -37,7 +37,7 @@ func initRewrite() { ...@@ -37,7 +37,7 @@ func initRewrite() {
// but there are problems with preserving formatting and also // but there are problems with preserving formatting and also
// with what a wildcard for a statement looks like. // with what a wildcard for a statement looks like.
func parseExpr(s string, what string) ast.Expr { func parseExpr(s string, what string) ast.Expr {
x, err := parser.ParseExpr("input", s, nil) x, err := parser.ParseExpr("input", s)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err) fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
os.Exit(2) os.Exit(2)
...@@ -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).Name() 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)
...@@ -139,7 +139,7 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool { ...@@ -139,7 +139,7 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
// of recursing down any further via reflection. // of recursing down any further via reflection.
p := pattern.Interface().(*ast.Ident) p := pattern.Interface().(*ast.Ident)
v := val.Interface().(*ast.Ident) v := val.Interface().(*ast.Ident)
return p == nil && v == nil || p != nil && v != nil && p.Name() == v.Name() return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
} }
p := reflect.Indirect(pattern) p := reflect.Indirect(pattern)
...@@ -194,7 +194,7 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) ...@@ -194,7 +194,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).Name() 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)
......
...@@ -41,11 +41,11 @@ func goFiles(dir string, allowMain bool) (files []string, imports map[string]str ...@@ -41,11 +41,11 @@ func goFiles(dir string, allowMain bool) (files []string, imports map[string]str
continue continue
} }
filename := path.Join(dir, d.Name) filename := path.Join(dir, d.Name)
pf, err := parser.ParseFile(filename, nil, nil, parser.ImportsOnly) pf, err := parser.ParseFile(filename, nil, parser.ImportsOnly)
if err != nil { if err != nil {
return nil, nil, "", err return nil, nil, "", err
} }
s := string(pf.Name.Name()) s := string(pf.Name.Name)
if s == "main" && !allowMain { if s == "main" && !allowMain {
continue continue
} }
......
...@@ -585,7 +585,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr { ...@@ -585,7 +585,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.Name()) 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)
...@@ -621,7 +621,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr { ...@@ -621,7 +621,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.Name()) 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.Name(), 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.Name(), &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.Name()) 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.Name(), 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.Name(), &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.Name()) 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.Name()] 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.Name(), &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.Name(), 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.Name()]; 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.Name() { 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.Name()) 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.Name()] l, ok := a.labels[s.Label.Name]
if !ok { if !ok {
pc := badPC pc := badPC
l = &label{name: s.Label.Name(), 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) fu ...@@ -1235,14 +1235,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) fu
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].Name(), 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].Name(), decl.OutNames[i].Pos(), t) bodyScope.DefineVar(decl.OutNames[i].Name, decl.OutNames[i].Pos(), t)
} else { } else {
bodyScope.DefineTemp(t) bodyScope.DefineTemp(t)
} }
......
...@@ -771,7 +771,7 @@ func typeListString(ts []Type, ns []*ast.Ident) string { ...@@ -771,7 +771,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].Name() + " " 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
...@@ -815,7 +815,7 @@ type FuncDecl struct { ...@@ -815,7 +815,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.Name() 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.Name()) _, _, def := a.block.Lookup(x.Name)
if def == nil { if def == nil {
a.diagAt(x, "%s: undefined", x.Name()) 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.Name()) 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.Name()) 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.Name(), def) log.Crashf("name %s has unknown type %T", x.Name, def)
return nil return nil
} }
...@@ -137,7 +137,7 @@ func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type ...@@ -137,7 +137,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].Name() name = names[i].Name
} else { } else {
if ts[i] == nil { if ts[i] == nil {
continue continue
...@@ -237,7 +237,7 @@ func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) ...@@ -237,7 +237,7 @@ func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool)
} }
if names[i] != nil { if names[i] != nil {
name := names[i].Name() 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++
...@@ -370,7 +370,7 @@ func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool { ...@@ -370,7 +370,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.Name(), 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
} }
......
...@@ -136,13 +136,13 @@ func (e *exprCode) Run() (Value, os.Error) { ...@@ -136,13 +136,13 @@ func (e *exprCode) Run() (Value, os.Error) {
} }
func (w *World) Compile(text string) (Code, os.Error) { func (w *World) Compile(text string) (Code, os.Error) {
stmts, err := parser.ParseStmtList("input", text, nil) stmts, err := parser.ParseStmtList("input", text)
if err == nil { if err == nil {
return w.CompileStmtList(stmts) return w.CompileStmtList(stmts)
} }
// Otherwise try as DeclList. // Otherwise try as DeclList.
decls, err1 := parser.ParseDeclList("input", text, nil) decls, err1 := parser.ParseDeclList("input", text)
if err1 == nil { if err1 == nil {
return w.CompileDeclList(decls) return w.CompileDeclList(decls)
} }
......
...@@ -141,7 +141,8 @@ type ( ...@@ -141,7 +141,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
Obj *Object // denoted object Name string // identifier name
Obj *Object // denoted object; or nil
} }
// An Ellipsis node stands for the "..." type in a // An Ellipsis node stands for the "..." type in a
...@@ -156,7 +157,7 @@ type ( ...@@ -156,7 +157,7 @@ type (
BasicLit struct { BasicLit struct {
token.Position // literal position token.Position // literal position
Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 'a', '\x7f', "foo" or `\m\n\o` Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o`
} }
// A FuncLit node represents a function literal. // A FuncLit node represents a function literal.
...@@ -166,7 +167,6 @@ type ( ...@@ -166,7 +167,6 @@ type (
} }
// A CompositeLit node represents a composite literal. // A CompositeLit node represents a composite literal.
//
CompositeLit struct { CompositeLit struct {
Type Expr // literal type Type Expr // literal type
Lbrace token.Position // position of "{" Lbrace token.Position // position of "{"
...@@ -218,6 +218,7 @@ type ( ...@@ -218,6 +218,7 @@ type (
// A StarExpr node represents an expression of the form "*" Expression. // A StarExpr node represents an expression of the form "*" Expression.
// Semantically it could be a unary "*" expression, or a pointer type. // Semantically it could be a unary "*" expression, or a pointer type.
//
StarExpr struct { StarExpr struct {
token.Position // position of "*" token.Position // position of "*"
X Expr // operand X Expr // operand
...@@ -233,7 +234,6 @@ type ( ...@@ -233,7 +234,6 @@ type (
} }
// A BinaryExpr node represents a binary expression. // A BinaryExpr node represents a binary expression.
//
BinaryExpr struct { BinaryExpr struct {
X Expr // left operand X Expr // left operand
OpPos token.Position // position of Op OpPos token.Position // position of Op
...@@ -330,6 +330,7 @@ func (x *KeyValueExpr) Pos() token.Position { return x.Key.Pos() } ...@@ -330,6 +330,7 @@ func (x *KeyValueExpr) Pos() token.Position { return x.Key.Pos() }
// exprNode() ensures that only expression/type nodes can be // exprNode() ensures that only expression/type nodes can be
// assigned to an ExprNode. // assigned to an ExprNode.
//
func (x *BadExpr) exprNode() {} func (x *BadExpr) exprNode() {}
func (x *Ident) exprNode() {} func (x *Ident) exprNode() {}
func (x *Ellipsis) exprNode() {} func (x *Ellipsis) exprNode() {}
...@@ -360,15 +361,15 @@ func (x *ChanType) exprNode() {} ...@@ -360,15 +361,15 @@ func (x *ChanType) exprNode() {}
var noPos token.Position var noPos token.Position
// NewIdent creates a new Ident without position and minimal object // NewIdent creates a new Ident without position.
// information. Useful for ASTs generated by code other than the Go // Useful for ASTs generated by code other than the Go parser.
// parser.
// //
func NewIdent(name string) *Ident { return &Ident{noPos, NewObj(Err, noPos, name)} } func NewIdent(name string) *Ident { return &Ident{noPos, name, nil} }
// 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 {
ch, _ := utf8.DecodeRuneInString(name) ch, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(ch) return unicode.IsUpper(ch)
...@@ -377,16 +378,13 @@ func IsExported(name string) bool { ...@@ -377,16 +378,13 @@ func IsExported(name string) bool {
// IsExported returns whether id 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 (id *Ident) IsExported() bool { return id.Obj.IsExported() } //
func (id *Ident) IsExported() bool { return IsExported(id.Name) }
// Name returns an identifier's name.
func (id *Ident) Name() string { return id.Obj.Name }
func (id *Ident) String() string { func (id *Ident) String() string {
if id != nil && id.Obj != nil { if id != nil {
return id.Obj.Name return id.Name
} }
return "<nil>" return "<nil>"
} }
...@@ -441,6 +439,7 @@ type ( ...@@ -441,6 +439,7 @@ type (
// An AssignStmt node represents an assignment or // An AssignStmt node represents an assignment or
// a short variable declaration. // a short variable declaration.
//
AssignStmt struct { AssignStmt struct {
Lhs []Expr Lhs []Expr
TokPos token.Position // position of Tok TokPos token.Position // position of Tok
...@@ -618,6 +617,7 @@ type ( ...@@ -618,6 +617,7 @@ type (
// A ValueSpec node represents a constant or variable declaration // A ValueSpec node represents a constant or variable declaration
// (ConstSpec or VarSpec production). // (ConstSpec or VarSpec production).
//
ValueSpec struct { ValueSpec struct {
Doc *CommentGroup // associated documentation; or nil Doc *CommentGroup // associated documentation; or nil
Names []*Ident // value names Names []*Ident // value names
...@@ -630,7 +630,7 @@ type ( ...@@ -630,7 +630,7 @@ type (
TypeSpec struct { TypeSpec struct {
Doc *CommentGroup // associated documentation; or nil Doc *CommentGroup // associated documentation; or nil
Name *Ident // type name Name *Ident // type name
Type Expr // *ArrayType, *StructType, *FuncType, *InterfaceType, *MapType, *ChanType or *Ident Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
Comment *CommentGroup // line comments; or nil Comment *CommentGroup // line comments; or nil
} }
) )
...@@ -734,6 +734,6 @@ type File struct { ...@@ -734,6 +734,6 @@ type File struct {
// //
type Package struct { type Package struct {
Name string // package name Name string // package name
Scope *Scope // package scope Scope *Scope // package scope; or nil
Files map[string]*File // Go source files by filename Files map[string]*File // Go source files by filename
} }
...@@ -197,7 +197,7 @@ type Filter func(string) bool ...@@ -197,7 +197,7 @@ type Filter func(string) bool
func filterIdentList(list []*Ident, f Filter) []*Ident { func filterIdentList(list []*Ident, f Filter) []*Ident {
j := 0 j := 0
for _, x := range list { for _, x := range list {
if f(x.Name()) { if f(x.Name) {
list[j] = x list[j] = x
j++ j++
} }
...@@ -212,7 +212,7 @@ func filterSpec(spec Spec, f Filter) bool { ...@@ -212,7 +212,7 @@ func filterSpec(spec Spec, f Filter) bool {
s.Names = filterIdentList(s.Names, f) s.Names = filterIdentList(s.Names, f)
return len(s.Names) > 0 return len(s.Names) > 0
case *TypeSpec: case *TypeSpec:
return f(s.Name.Name()) return f(s.Name.Name)
} }
return false return false
} }
...@@ -236,7 +236,7 @@ func filterDecl(decl Decl, f Filter) bool { ...@@ -236,7 +236,7 @@ func filterDecl(decl Decl, f Filter) bool {
d.Specs = filterSpecList(d.Specs, f) d.Specs = filterSpecList(d.Specs, f)
return len(d.Specs) > 0 return len(d.Specs) > 0
case *FuncDecl: case *FuncDecl:
return f(d.Name.Name()) return f(d.Name.Name)
} }
return false return false
} }
...@@ -397,7 +397,7 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File { ...@@ -397,7 +397,7 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
// entities (const, type, vars) if // entities (const, type, vars) if
// multiple declarations are common. // multiple declarations are common.
if f, isFun := d.(*FuncDecl); isFun { if f, isFun := d.(*FuncDecl); isFun {
name := f.Name.Name() name := f.Name.Name
if j, exists := funcs[name]; exists { if j, exists := funcs[name]; exists {
// function declared already // function declared already
if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil { if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil {
......
...@@ -4,13 +4,11 @@ ...@@ -4,13 +4,11 @@
package ast package ast
import "go/token"
type ObjKind int type ObjKind int
// The list of possible Object kinds. // The list of possible Object kinds.
const ( const (
Err ObjKind = iota // object kind unknown (forward reference or error) Bad ObjKind = iota // bad object
Pkg // package Pkg // package
Con // constant Con // constant
Typ // type Typ // type
...@@ -20,7 +18,7 @@ const ( ...@@ -20,7 +18,7 @@ const (
var objKindStrings = [...]string{ var objKindStrings = [...]string{
Err: "<unknown object kind>", Bad: "bad",
Pkg: "package", Pkg: "package",
Con: "const", Con: "const",
Typ: "type", Typ: "type",
...@@ -37,13 +35,13 @@ func (kind ObjKind) String() string { return objKindStrings[kind] } ...@@ -37,13 +35,13 @@ func (kind ObjKind) String() string { return objKindStrings[kind] }
// //
type Object struct { type Object struct {
Kind ObjKind Kind ObjKind
Pos token.Position // declaration position Name string // declared name
Name string // declared name Decl interface{} // corresponding Field, xxxSpec or FuncDecl
} }
func NewObj(kind ObjKind, pos token.Position, name string) *Object { func NewObj(kind ObjKind, name string) *Object {
return &Object{kind, pos, name} return &Object{kind, name, nil}
} }
...@@ -57,12 +55,43 @@ func (obj *Object) IsExported() bool { return IsExported(obj.Name) } ...@@ -57,12 +55,43 @@ func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
// //
type Scope struct { type Scope struct {
Outer *Scope Outer *Scope
Objects map[string]*Object Objects []*Object // in declaration order
// Implementation note: In some cases (struct fields,
// function parameters) we need the source order of
// variables. Thus for now, we store scope entries
// in a linear list. If scopes become very large
// (say, for packages), we may need to change this
// to avoid slow lookups.
} }
// 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]*Object)} } func NewScope(outer *Scope) *Scope {
const n = 4 // initial scope capacity, must be > 0
return &Scope{outer, make([]*Object, 0, n)}
}
func (s *Scope) append(obj *Object) {
n := len(s.Objects)
if n >= cap(s.Objects) {
new := make([]*Object, 2*n)
copy(new, s.Objects)
s.Objects = new
}
s.Objects = s.Objects[0 : n+1]
s.Objects[n] = obj
}
func (s *Scope) lookup(name string) *Object {
for _, obj := range s.Objects {
if obj.Name == name {
return obj
}
}
return nil
}
// Declare attempts to insert a named object into the scope s. // Declare attempts to insert a named object into the scope s.
...@@ -71,12 +100,12 @@ func NewScope(outer *Scope) *Scope { return &Scope{outer, make(map[string]*Objec ...@@ -71,12 +100,12 @@ func NewScope(outer *Scope) *Scope { return &Scope{outer, make(map[string]*Objec
// scope remains unchanged and Declare returns the object found // scope remains unchanged and Declare returns the object found
// in the scope instead. // in the scope instead.
func (s *Scope) Declare(obj *Object) *Object { func (s *Scope) Declare(obj *Object) *Object {
decl, found := s.Objects[obj.Name] alt := s.lookup(obj.Name)
if !found { if alt == nil {
s.Objects[obj.Name] = obj s.append(obj)
decl = obj alt = obj
} }
return decl return alt
} }
...@@ -85,7 +114,7 @@ func (s *Scope) Declare(obj *Object) *Object { ...@@ -85,7 +114,7 @@ func (s *Scope) Declare(obj *Object) *Object {
// //
func (s *Scope) Lookup(name string) *Object { func (s *Scope) Lookup(name string) *Object {
for ; s != nil; s = s.Outer { for ; s != nil; s = s.Outer {
if obj, found := s.Objects[name]; found { if obj := s.lookup(name); obj != nil {
return obj return obj
} }
} }
......
...@@ -77,7 +77,7 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) { ...@@ -77,7 +77,7 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
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.Name()) 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 {
...@@ -108,7 +108,7 @@ func baseTypeName(typ ast.Expr) string { ...@@ -108,7 +108,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.Name()) return string(t.Name)
} }
case *ast.StarExpr: case *ast.StarExpr:
return baseTypeName(t.X) return baseTypeName(t.X)
...@@ -173,7 +173,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) { ...@@ -173,7 +173,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
// at least one f with associated documentation is stored in table, if there // at least one f with associated documentation is stored in table, if there
// are multiple f's with the same name. // are multiple f's with the same name.
func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) { func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
name := f.Name.Name() name := f.Name.Name
if g, exists := table[name]; exists && g.Doc != nil { if g, exists := table[name]; exists && g.Doc != nil {
// a function with the same name has already been registered; // a function with the same name has already been registered;
// since it has documentation, assume f is simply another // since it has documentation, assume f is simply another
...@@ -188,7 +188,7 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) { ...@@ -188,7 +188,7 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
func (doc *docReader) addFunc(fun *ast.FuncDecl) { func (doc *docReader) addFunc(fun *ast.FuncDecl) {
name := fun.Name.Name() 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 {
...@@ -325,7 +325,7 @@ func (doc *docReader) addFile(src *ast.File) { ...@@ -325,7 +325,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.Name()) r.init(file.Name.Name)
r.addFile(file) r.addFile(file)
return r.newDoc("", nil) return r.newDoc("", nil)
} }
...@@ -370,9 +370,9 @@ func declName(d *ast.GenDecl) string { ...@@ -370,9 +370,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].Name() return v.Names[0].Name
case *ast.TypeSpec: case *ast.TypeSpec:
return v.Name.Name() return v.Name.Name
} }
return "" return ""
...@@ -434,7 +434,7 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc { ...@@ -434,7 +434,7 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
if f.Recv != nil { if f.Recv != nil {
doc.Recv = f.Recv.List[0].Type doc.Recv = f.Recv.List[0].Type
} }
doc.Name = f.Name.Name() doc.Name = f.Name.Name
doc.Decl = f doc.Decl = f
d[i] = doc d[i] = doc
i++ i++
...@@ -467,7 +467,7 @@ func (p sortTypeDoc) Less(i, j int) bool { ...@@ -467,7 +467,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.Name(), p[j].Type.Name.Name(); 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
...@@ -587,12 +587,12 @@ func matchDecl(d *ast.GenDecl, f Filter) bool { ...@@ -587,12 +587,12 @@ func matchDecl(d *ast.GenDecl, f Filter) 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 f(name.Name()) { if f(name.Name) {
return true return true
} }
} }
case *ast.TypeSpec: case *ast.TypeSpec:
if f(v.Name.Name()) { if f(v.Name.Name) {
return true return true
} }
} }
......
...@@ -57,52 +57,52 @@ func (p *parser) parseEOF() os.Error { ...@@ -57,52 +57,52 @@ func (p *parser) parseEOF() os.Error {
// ParseExpr parses a Go expression and returns the corresponding // ParseExpr parses a Go expression and returns the corresponding
// AST node. The filename, src, and scope arguments have the same interpretation // AST node. The filename and src arguments have the same interpretation
// as for ParseFile. If there is an error, the result expression // as for ParseFile. If there is an error, the result expression
// may be nil or contain a partial AST. // may be nil or contain a partial AST.
// //
func ParseExpr(filename string, src interface{}, scope *ast.Scope) (ast.Expr, os.Error) { func ParseExpr(filename string, src interface{}) (ast.Expr, os.Error) {
data, err := readSource(filename, src) data, err := readSource(filename, src)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var p parser var p parser
p.init(filename, data, scope, 0) p.init(filename, data, 0)
return p.parseExpr(), p.parseEOF() return p.parseExpr(), p.parseEOF()
} }
// ParseStmtList parses a list of Go statements and returns the list // ParseStmtList parses a list of Go statements and returns the list
// of corresponding AST nodes. The filename, src, and scope arguments have the same // of corresponding AST nodes. The filename and src arguments have the same
// interpretation as for ParseFile. If there is an error, the node // interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs. // list may be nil or contain partial ASTs.
// //
func ParseStmtList(filename string, src interface{}, scope *ast.Scope) ([]ast.Stmt, os.Error) { func ParseStmtList(filename string, src interface{}) ([]ast.Stmt, os.Error) {
data, err := readSource(filename, src) data, err := readSource(filename, src)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var p parser var p parser
p.init(filename, data, scope, 0) p.init(filename, data, 0)
return p.parseStmtList(), p.parseEOF() return p.parseStmtList(), p.parseEOF()
} }
// ParseDeclList parses a list of Go declarations and returns the list // ParseDeclList parses a list of Go declarations and returns the list
// of corresponding AST nodes. The filename, src, and scope arguments have the same // of corresponding AST nodes. The filename and src arguments have the same
// interpretation as for ParseFile. If there is an error, the node // interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs. // list may be nil or contain partial ASTs.
// //
func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.Decl, os.Error) { func ParseDeclList(filename string, src interface{}) ([]ast.Decl, os.Error) {
data, err := readSource(filename, src) data, err := readSource(filename, src)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var p parser var p parser
p.init(filename, data, scope, 0) p.init(filename, data, 0)
return p.parseDeclList(), p.parseEOF() return p.parseDeclList(), p.parseEOF()
} }
...@@ -116,11 +116,6 @@ func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.De ...@@ -116,11 +116,6 @@ func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.De
// //
// If src == nil, ParseFile parses the file specified by filename. // If src == nil, ParseFile parses the file specified by filename.
// //
// If scope != nil, it is the immediately surrounding scope for the file
// (the package scope) and it is used to lookup and declare identifiers.
// When parsing multiple files belonging to a package, the same scope should
// be provided to all files.
//
// The mode parameter controls the amount of source text parsed and other // The mode parameter controls the amount of source text parsed and other
// optional parser functionality. // optional parser functionality.
// //
...@@ -130,14 +125,14 @@ func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.De ...@@ -130,14 +125,14 @@ func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.De
// representing the fragments of erroneous source code). Multiple errors // representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position. // are returned via a scanner.ErrorList which is sorted by file position.
// //
func ParseFile(filename string, src interface{}, scope *ast.Scope, mode uint) (*ast.File, os.Error) { func ParseFile(filename string, src interface{}, mode uint) (*ast.File, os.Error) {
data, err := readSource(filename, src) data, err := readSource(filename, src)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var p parser var p parser
p.init(filename, data, scope, mode) p.init(filename, data, mode)
return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
} }
...@@ -150,14 +145,14 @@ func ParseFile(filename string, src interface{}, scope *ast.Scope, mode uint) (* ...@@ -150,14 +145,14 @@ func ParseFile(filename string, src interface{}, scope *ast.Scope, mode uint) (*
// be incomplete (missing packages and/or incomplete packages) and the first // be incomplete (missing packages and/or incomplete packages) and the first
// error encountered is returned. // error encountered is returned.
// //
func ParseFiles(filenames []string, scope *ast.Scope, mode uint) (pkgs map[string]*ast.Package, first os.Error) { func ParseFiles(filenames []string, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
pkgs = make(map[string]*ast.Package) pkgs = make(map[string]*ast.Package)
for _, filename := range filenames { for _, filename := range filenames {
if src, err := ParseFile(filename, nil, scope, mode); err == nil { if src, err := ParseFile(filename, nil, mode); err == nil {
name := src.Name.Name() name := src.Name.Name
pkg, found := pkgs[name] pkg, found := pkgs[name]
if !found { if !found {
pkg = &ast.Package{name, scope, make(map[string]*ast.File)} pkg = &ast.Package{name, nil, make(map[string]*ast.File)}
pkgs[name] = pkg pkgs[name] = pkg
} }
pkg.Files[filename] = src pkg.Files[filename] = src
...@@ -201,6 +196,5 @@ func ParseDir(path string, filter func(*os.FileInfo) bool, mode uint) (map[strin ...@@ -201,6 +196,5 @@ func ParseDir(path string, filter func(*os.FileInfo) bool, mode uint) (map[strin
} }
filenames = filenames[0:n] filenames = filenames[0:n]
var scope *ast.Scope = nil // for now tracking of declarations is disabled return ParseFiles(filenames, mode)
return ParseFiles(filenames, scope, mode)
} }
This diff is collapsed.
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
package parser package parser
import ( import (
"go/ast"
"os" "os"
"testing" "testing"
) )
...@@ -21,7 +20,7 @@ var illegalInputs = []interface{}{ ...@@ -21,7 +20,7 @@ var illegalInputs = []interface{}{
func TestParseIllegalInputs(t *testing.T) { func TestParseIllegalInputs(t *testing.T) {
for _, src := range illegalInputs { for _, src := range illegalInputs {
_, err := ParseFile("", src, nil, 0) _, err := ParseFile("", src, 0)
if err == nil { if err == nil {
t.Errorf("ParseFile(%v) should have failed", src) t.Errorf("ParseFile(%v) should have failed", src)
} }
...@@ -46,7 +45,7 @@ var validPrograms = []interface{}{ ...@@ -46,7 +45,7 @@ var validPrograms = []interface{}{
func TestParseValidPrograms(t *testing.T) { func TestParseValidPrograms(t *testing.T) {
for _, src := range validPrograms { for _, src := range validPrograms {
_, err := ParseFile("", src, ast.NewScope(nil), 0) _, err := ParseFile("", src, 0)
if err != nil { if err != nil {
t.Errorf("ParseFile(%q): %v", src, err) t.Errorf("ParseFile(%q): %v", src, err)
} }
...@@ -62,7 +61,7 @@ var validFiles = []string{ ...@@ -62,7 +61,7 @@ var validFiles = []string{
func TestParse3(t *testing.T) { func TestParse3(t *testing.T) {
for _, filename := range validFiles { for _, filename := range validFiles {
_, err := ParseFile(filename, nil, ast.NewScope(nil), 0) _, err := ParseFile(filename, nil, 0)
if err != nil { if err != nil {
t.Errorf("ParseFile(%s): %v", filename, err) t.Errorf("ParseFile(%s): %v", filename, err)
} }
......
...@@ -335,7 +335,7 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) { ...@@ -335,7 +335,7 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) {
if i > 0 { if i > 0 {
size += 2 // ", " size += 2 // ", "
} }
size += len(x.Name()) size += len(x.Name)
if size >= maxSize { if size >= maxSize {
break break
} }
......
...@@ -780,7 +780,7 @@ func (p *printer) print(args ...interface{}) { ...@@ -780,7 +780,7 @@ func (p *printer) print(args ...interface{}) {
if p.Styler != nil { if p.Styler != nil {
data, tag = p.Styler.Ident(x) data, tag = p.Styler.Ident(x)
} else { } else {
data = []byte(x.Name()) data = []byte(x.Name)
} }
tok = token.IDENT tok = token.IDENT
case *ast.BasicLit: case *ast.BasicLit:
......
...@@ -43,7 +43,7 @@ const ( ...@@ -43,7 +43,7 @@ const (
func check(t *testing.T, source, golden string, mode checkMode) { func check(t *testing.T, source, golden string, mode checkMode) {
// parse source // parse source
prog, err := parser.ParseFile(source, nil, nil, parser.ParseComments) prog, err := parser.ParseFile(source, nil, parser.ParseComments)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
......
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