mirror of
https://github.com/golang/go
synced 2024-11-21 15:24:45 -07:00
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
This commit is contained in:
parent
be97fa4c79
commit
1f9dfa294f
@ -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}
|
|||||||
{.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 (
|
|||||||
)
|
)
|
||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
// 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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
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) {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
if !found {
|
//
|
||||||
n = s.count
|
// TODO(gri): Consider making this a mapping from popup info
|
||||||
s.objmap[obj] = n
|
// (for that name) to id, instead of *ast.Object
|
||||||
s.count++
|
// 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
|
||||||
}
|
}
|
||||||
return n
|
id, found := s.objmap[obj]
|
||||||
|
if !found {
|
||||||
|
// first occurence
|
||||||
|
id = s.idcount
|
||||||
|
s.objmap[obj] = id
|
||||||
|
s.idcount++
|
||||||
|
}
|
||||||
|
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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{
|
|||||||
"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 {
|
|||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
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 (
|
|||||||
|
|
||||||
// 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 {
|
|||||||
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() {
|
|||||||
// 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 {
|
|||||||
// 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 {
|
|||||||
// 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)
|
|||||||
|
|
||||||
// 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
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
// 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) {
|
|||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
|||||||
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,
|
|||||||
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) {
|
|||||||
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
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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
|
|||||||
// 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 (
|
|||||||
// 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 (
|
|||||||
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 (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 (
|
|||||||
|
|
||||||
// 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 (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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() }
|
|||||||
|
|
||||||
// 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() {}
|
|||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
// 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 (
|
|||||||
|
|
||||||
// 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 (
|
|||||||
|
|
||||||
// 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 (
|
|||||||
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 {
|
|||||||
//
|
//
|
||||||
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
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
// 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 @@
|
|||||||
|
|
||||||
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 (
|
|||||||
|
|
||||||
|
|
||||||
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] }
|
|||||||
//
|
//
|
||||||
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) }
|
|||||||
//
|
//
|
||||||
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
|
|||||||
// 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 {
|
|||||||
//
|
//
|
||||||
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) {
|
|||||||
|
|
||||||
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 {
|
|||||||
// 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) {
|
|||||||
// 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) {
|
|||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
// 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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
|
|
||||||
// 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
|
|||||||
//
|
//
|
||||||
// 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
|
|||||||
// 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) (*
|
|||||||
// 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
|
|||||||
}
|
}
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,6 @@ type parser struct {
|
|||||||
|
|
||||||
// Non-syntactic parser control
|
// Non-syntactic parser control
|
||||||
exprLev int // < 0: in control clause, >= 0: in expression
|
exprLev int // < 0: in control clause, >= 0: in expression
|
||||||
|
|
||||||
// Scopes
|
|
||||||
checkDecl bool // if set, check declarations
|
|
||||||
pkgScope *ast.Scope
|
|
||||||
fileScope *ast.Scope
|
|
||||||
funcScope *ast.Scope
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -75,16 +69,10 @@ func scannerMode(mode uint) uint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) init(filename string, src []byte, scope *ast.Scope, 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)
|
||||||
if scope != nil {
|
|
||||||
p.checkDecl = true
|
|
||||||
} else {
|
|
||||||
scope = ast.NewScope(nil) // provide a dummy scope
|
|
||||||
}
|
|
||||||
p.pkgScope = scope
|
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,39 +264,31 @@ func (p *parser) expectSemi() {
|
|||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Scope support
|
// Identifiers
|
||||||
|
|
||||||
func (p *parser) openScope() *ast.Scope {
|
func (p *parser) parseIdent() *ast.Ident {
|
||||||
p.funcScope = ast.NewScope(p.funcScope)
|
pos := p.pos
|
||||||
return p.funcScope
|
name := "_"
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) closeScope() { p.funcScope = p.funcScope.Outer }
|
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseIdent(kind ast.ObjKind) *ast.Ident {
|
|
||||||
obj := ast.NewObj(kind, p.pos, "_")
|
|
||||||
if p.tok == token.IDENT {
|
if p.tok == token.IDENT {
|
||||||
obj.Name = string(p.lit)
|
name = string(p.lit)
|
||||||
p.next()
|
p.next()
|
||||||
} else {
|
} 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{pos, name, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseIdentList(kind ast.ObjKind) []*ast.Ident {
|
func (p *parser) parseIdentList() []*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(kind))
|
list.Push(p.parseIdent())
|
||||||
for p.tok == token.COMMA {
|
for p.tok == token.COMMA {
|
||||||
p.next()
|
p.next()
|
||||||
list.Push(p.parseIdent(kind))
|
list.Push(p.parseIdent())
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert vector
|
// convert vector
|
||||||
@ -321,82 +301,6 @@ func (p *parser) parseIdentList(kind ast.ObjKind) []*ast.Ident {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) declIdent(scope *ast.Scope, id *ast.Ident) {
|
|
||||||
decl := scope.Declare(id.Obj)
|
|
||||||
if p.checkDecl && decl != id.Obj {
|
|
||||||
if decl.Kind == ast.Err {
|
|
||||||
// declared object is a forward declaration - update it
|
|
||||||
*decl = *id.Obj
|
|
||||||
id.Obj = decl
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.Error(id.Pos(), "'"+id.Name()+"' declared already at "+decl.Pos.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) declIdentList(scope *ast.Scope, list []*ast.Ident) {
|
|
||||||
for _, id := range list {
|
|
||||||
p.declIdent(scope, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) declFieldList(scope *ast.Scope, list []*ast.Field) {
|
|
||||||
for _, f := range list {
|
|
||||||
p.declIdentList(scope, f.Names)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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.funcScope.Lookup(name)
|
|
||||||
p.next()
|
|
||||||
} else {
|
|
||||||
p.expect(token.IDENT) // use expect() error handling
|
|
||||||
}
|
|
||||||
if obj == nil {
|
|
||||||
// No declaration found: either we are outside any function
|
|
||||||
// (p.funcScope == nil) or the identifier is not declared
|
|
||||||
// in any function. Try the file and package scope.
|
|
||||||
obj = p.fileScope.Lookup(name) // file scope is nested in package scope
|
|
||||||
if obj == nil {
|
|
||||||
// No declaration found anywhere: track as
|
|
||||||
// unresolved identifier in the package scope.
|
|
||||||
obj = ast.NewObj(ast.Err, pos, name)
|
|
||||||
p.pkgScope.Declare(obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &ast.Ident{pos, obj}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) findIdentInScope(scope *ast.Scope) *ast.Ident {
|
|
||||||
pos := p.pos
|
|
||||||
name := "_"
|
|
||||||
var obj *ast.Object
|
|
||||||
if p.tok == token.IDENT {
|
|
||||||
name = string(p.lit)
|
|
||||||
obj = scope.Lookup(name)
|
|
||||||
p.next()
|
|
||||||
} else {
|
|
||||||
p.expect(token.IDENT) // use expect() error handling
|
|
||||||
}
|
|
||||||
if obj == nil {
|
|
||||||
// TODO(gri) At the moment we always arrive here because
|
|
||||||
// we don't track the lookup scope (and sometimes
|
|
||||||
// we can't). Just create a useable ident for now.
|
|
||||||
obj = ast.NewObj(ast.Err, pos, name)
|
|
||||||
}
|
|
||||||
return &ast.Ident{pos, obj}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Common productions
|
// Common productions
|
||||||
|
|
||||||
@ -450,11 +354,11 @@ func (p *parser) parseQualifiedIdent() ast.Expr {
|
|||||||
defer un(trace(p, "QualifiedIdent"))
|
defer un(trace(p, "QualifiedIdent"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var x ast.Expr = p.findIdent()
|
var x ast.Expr = p.parseIdent()
|
||||||
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.findIdentInScope(nil)
|
sel := p.parseIdent()
|
||||||
x = &ast.SelectorExpr{x, sel}
|
x = &ast.SelectorExpr{x, sel}
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
@ -497,7 +401,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")
|
||||||
ident = &ast.Ident{pos, ast.NewObj(ast.Err, pos, "_")}
|
ident = &ast.Ident{pos, "_", nil}
|
||||||
}
|
}
|
||||||
idents[i] = ident
|
idents[i] = ident
|
||||||
}
|
}
|
||||||
@ -565,9 +469,6 @@ func (p *parser) parseStructType() *ast.StructType {
|
|||||||
fields[i] = x.(*ast.Field)
|
fields[i] = x.(*ast.Field)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gri) The struct scope shouldn't get lost.
|
|
||||||
p.declFieldList(ast.NewScope(nil), fields)
|
|
||||||
|
|
||||||
return &ast.StructType{pos, &ast.FieldList{lbrace, fields, rbrace}, false}
|
return &ast.StructType{pos, &ast.FieldList{lbrace, fields, rbrace}, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,7 +556,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(ast.Var)
|
idents := p.parseIdentList()
|
||||||
typ := p.parseVarType(ellipsisOk)
|
typ := p.parseVarType(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 {
|
||||||
@ -682,7 +583,7 @@ func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
|
func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
|
||||||
if p.trace {
|
if p.trace {
|
||||||
defer un(trace(p, "Parameters"))
|
defer un(trace(p, "Parameters"))
|
||||||
}
|
}
|
||||||
@ -691,7 +592,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
|
|||||||
lparen := p.expect(token.LPAREN)
|
lparen := p.expect(token.LPAREN)
|
||||||
if p.tok != token.RPAREN {
|
if p.tok != token.RPAREN {
|
||||||
params = p.parseParameterList(ellipsisOk)
|
params = p.parseParameterList(ellipsisOk)
|
||||||
p.declFieldList(scope, params)
|
|
||||||
}
|
}
|
||||||
rparen := p.expect(token.RPAREN)
|
rparen := p.expect(token.RPAREN)
|
||||||
|
|
||||||
@ -699,13 +599,13 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
|
func (p *parser) parseResult() *ast.FieldList {
|
||||||
if p.trace {
|
if p.trace {
|
||||||
defer un(trace(p, "Result"))
|
defer un(trace(p, "Result"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.tok == token.LPAREN {
|
if p.tok == token.LPAREN {
|
||||||
return p.parseParameters(scope, false)
|
return p.parseParameters(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
typ := p.tryType()
|
typ := p.tryType()
|
||||||
@ -719,28 +619,27 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
|
func (p *parser) parseSignature() (params, results *ast.FieldList) {
|
||||||
if p.trace {
|
if p.trace {
|
||||||
defer un(trace(p, "Signature"))
|
defer un(trace(p, "Signature"))
|
||||||
}
|
}
|
||||||
|
|
||||||
params = p.parseParameters(scope, true)
|
params = p.parseParameters(true)
|
||||||
results = p.parseResult(scope)
|
results = p.parseResult()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseFuncType() (*ast.Scope, *ast.FuncType) {
|
func (p *parser) parseFuncType() *ast.FuncType {
|
||||||
if p.trace {
|
if p.trace {
|
||||||
defer un(trace(p, "FuncType"))
|
defer un(trace(p, "FuncType"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pos := p.expect(token.FUNC)
|
pos := p.expect(token.FUNC)
|
||||||
scope := ast.NewScope(p.funcScope)
|
params, results := p.parseSignature()
|
||||||
params, results := p.parseSignature(scope)
|
|
||||||
|
|
||||||
return scope, &ast.FuncType{pos, params, results}
|
return &ast.FuncType{pos, params, results}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -756,7 +655,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
|
|||||||
if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
|
if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
|
||||||
// method
|
// method
|
||||||
idents = []*ast.Ident{ident}
|
idents = []*ast.Ident{ident}
|
||||||
params, results := p.parseSignature(ast.NewScope(p.funcScope))
|
params, results := p.parseSignature()
|
||||||
typ = &ast.FuncType{noPos, params, results}
|
typ = &ast.FuncType{noPos, params, results}
|
||||||
} else {
|
} else {
|
||||||
// embedded interface
|
// embedded interface
|
||||||
@ -787,9 +686,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
|
|||||||
methods[i] = x.(*ast.Field)
|
methods[i] = x.(*ast.Field)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gri) The interface scope shouldn't get lost.
|
|
||||||
p.declFieldList(ast.NewScope(nil), methods)
|
|
||||||
|
|
||||||
return &ast.InterfaceType{pos, &ast.FieldList{lbrace, methods, rbrace}, false}
|
return &ast.InterfaceType{pos, &ast.FieldList{lbrace, methods, rbrace}, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -844,8 +740,7 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
|
|||||||
case token.MUL:
|
case token.MUL:
|
||||||
return p.parsePointerType()
|
return p.parsePointerType()
|
||||||
case token.FUNC:
|
case token.FUNC:
|
||||||
_, typ := p.parseFuncType()
|
return p.parseFuncType()
|
||||||
return typ
|
|
||||||
case token.INTERFACE:
|
case token.INTERFACE:
|
||||||
return p.parseInterfaceType()
|
return p.parseInterfaceType()
|
||||||
case token.MAP:
|
case token.MAP:
|
||||||
@ -894,20 +789,15 @@ func (p *parser) parseStmtList() []ast.Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
|
func (p *parser) parseBody() *ast.BlockStmt {
|
||||||
if p.trace {
|
if p.trace {
|
||||||
defer un(trace(p, "Body"))
|
defer un(trace(p, "Body"))
|
||||||
}
|
}
|
||||||
|
|
||||||
savedScope := p.funcScope
|
|
||||||
p.funcScope = scope
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
p.funcScope = savedScope
|
|
||||||
|
|
||||||
return &ast.BlockStmt{lbrace, list, rbrace}
|
return &ast.BlockStmt{lbrace, list, rbrace}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -917,9 +807,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
|
|||||||
defer un(trace(p, "BlockStmt"))
|
defer un(trace(p, "BlockStmt"))
|
||||||
}
|
}
|
||||||
|
|
||||||
p.openScope()
|
|
||||||
defer p.closeScope()
|
|
||||||
|
|
||||||
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)
|
||||||
@ -936,14 +823,14 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
|
|||||||
defer un(trace(p, "FuncTypeOrLit"))
|
defer un(trace(p, "FuncTypeOrLit"))
|
||||||
}
|
}
|
||||||
|
|
||||||
scope, typ := p.parseFuncType()
|
typ := p.parseFuncType()
|
||||||
if p.tok != token.LBRACE {
|
if p.tok != token.LBRACE {
|
||||||
// function type only
|
// function type only
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
p.exprLev++
|
p.exprLev++
|
||||||
body := p.parseBody(scope)
|
body := p.parseBody()
|
||||||
p.exprLev--
|
p.exprLev--
|
||||||
|
|
||||||
return &ast.FuncLit{typ, body}
|
return &ast.FuncLit{typ, body}
|
||||||
@ -960,7 +847,7 @@ func (p *parser) parseOperand() ast.Expr {
|
|||||||
|
|
||||||
switch p.tok {
|
switch p.tok {
|
||||||
case token.IDENT:
|
case token.IDENT:
|
||||||
return p.findIdent()
|
return p.parseIdent()
|
||||||
|
|
||||||
case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
|
case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
|
||||||
x := &ast.BasicLit{p.pos, p.tok, p.lit}
|
x := &ast.BasicLit{p.pos, p.tok, p.lit}
|
||||||
@ -1000,7 +887,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.findIdentInScope(nil)
|
sel := p.parseIdent()
|
||||||
return &ast.SelectorExpr{x, sel}
|
return &ast.SelectorExpr{x, sel}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1445,7 +1332,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.findIdentInScope(nil)
|
s.Label = p.parseIdent()
|
||||||
}
|
}
|
||||||
p.expectSemi()
|
p.expectSemi()
|
||||||
|
|
||||||
@ -1501,10 +1388,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
|
|||||||
defer un(trace(p, "IfStmt"))
|
defer un(trace(p, "IfStmt"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IfStmt block
|
|
||||||
p.openScope()
|
|
||||||
defer p.closeScope()
|
|
||||||
|
|
||||||
pos := p.expect(token.IF)
|
pos := p.expect(token.IF)
|
||||||
s1, s2, _ := p.parseControlClause(false)
|
s1, s2, _ := p.parseControlClause(false)
|
||||||
body := p.parseBlockStmt()
|
body := p.parseBlockStmt()
|
||||||
@ -1525,10 +1408,6 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
|
|||||||
defer un(trace(p, "CaseClause"))
|
defer un(trace(p, "CaseClause"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaseClause block
|
|
||||||
p.openScope()
|
|
||||||
defer p.closeScope()
|
|
||||||
|
|
||||||
// SwitchCase
|
// SwitchCase
|
||||||
pos := p.pos
|
pos := p.pos
|
||||||
var x []ast.Expr
|
var x []ast.Expr
|
||||||
@ -1567,10 +1446,6 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
|
|||||||
defer un(trace(p, "TypeCaseClause"))
|
defer un(trace(p, "TypeCaseClause"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeCaseClause block
|
|
||||||
p.openScope()
|
|
||||||
defer p.closeScope()
|
|
||||||
|
|
||||||
// TypeSwitchCase
|
// TypeSwitchCase
|
||||||
pos := p.pos
|
pos := p.pos
|
||||||
var types []ast.Expr
|
var types []ast.Expr
|
||||||
@ -1607,10 +1482,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
|
|||||||
defer un(trace(p, "SwitchStmt"))
|
defer un(trace(p, "SwitchStmt"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SwitchStmt block
|
|
||||||
p.openScope()
|
|
||||||
defer p.closeScope()
|
|
||||||
|
|
||||||
pos := p.expect(token.SWITCH)
|
pos := p.expect(token.SWITCH)
|
||||||
s1, s2, _ := p.parseControlClause(false)
|
s1, s2, _ := p.parseControlClause(false)
|
||||||
|
|
||||||
@ -1645,10 +1516,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
|
|||||||
defer un(trace(p, "CommClause"))
|
defer un(trace(p, "CommClause"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommClause block
|
|
||||||
p.openScope()
|
|
||||||
defer p.closeScope()
|
|
||||||
|
|
||||||
// CommCase
|
// CommCase
|
||||||
pos := p.pos
|
pos := p.pos
|
||||||
var tok token.Token
|
var tok token.Token
|
||||||
@ -1709,10 +1576,6 @@ func (p *parser) parseForStmt() ast.Stmt {
|
|||||||
defer un(trace(p, "ForStmt"))
|
defer un(trace(p, "ForStmt"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForStmt block
|
|
||||||
p.openScope()
|
|
||||||
defer p.closeScope()
|
|
||||||
|
|
||||||
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()
|
body := p.parseBlockStmt()
|
||||||
@ -1825,14 +1688,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, ast.NewObj(ast.Pkg, p.pos, ".")}
|
ident = &ast.Ident{p.pos, ".", nil}
|
||||||
p.next()
|
p.next()
|
||||||
} else if p.tok == token.IDENT {
|
} else if p.tok == token.IDENT {
|
||||||
ident = p.parseIdent(ast.Pkg)
|
ident = p.parseIdent()
|
||||||
// TODO(gri) Make sure the ident is not already declared in the
|
|
||||||
// package scope. Also, cannot add the same name to
|
|
||||||
// the package scope later.
|
|
||||||
p.declIdent(p.fileScope, ident)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var path *ast.BasicLit
|
var path *ast.BasicLit
|
||||||
@ -1853,23 +1712,13 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
|
|||||||
defer un(trace(p, "ConstSpec"))
|
defer un(trace(p, "ConstSpec"))
|
||||||
}
|
}
|
||||||
|
|
||||||
idents := p.parseIdentList(ast.Con)
|
idents := p.parseIdentList()
|
||||||
if p.funcScope == nil {
|
|
||||||
// the scope of a constant outside any function
|
|
||||||
// is the package scope
|
|
||||||
p.declIdentList(p.pkgScope, idents)
|
|
||||||
}
|
|
||||||
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 {
|
||||||
p.expect(token.ASSIGN)
|
p.expect(token.ASSIGN)
|
||||||
values = p.parseExprList()
|
values = p.parseExprList()
|
||||||
}
|
}
|
||||||
if p.funcScope != nil {
|
|
||||||
// the scope of a constant inside a function
|
|
||||||
// begins after the the ConstSpec
|
|
||||||
p.declIdentList(p.funcScope, idents)
|
|
||||||
}
|
|
||||||
p.expectSemi()
|
p.expectSemi()
|
||||||
|
|
||||||
return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
|
return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
|
||||||
@ -1881,15 +1730,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
|
|||||||
defer un(trace(p, "TypeSpec"))
|
defer un(trace(p, "TypeSpec"))
|
||||||
}
|
}
|
||||||
|
|
||||||
ident := p.parseIdent(ast.Typ)
|
ident := p.parseIdent()
|
||||||
// the scope of a type outside any function is
|
|
||||||
// the package scope; the scope of a type inside
|
|
||||||
// a function starts at the type identifier
|
|
||||||
scope := p.funcScope
|
|
||||||
if scope == nil {
|
|
||||||
scope = p.pkgScope
|
|
||||||
}
|
|
||||||
p.declIdent(scope, ident)
|
|
||||||
typ := p.parseType()
|
typ := p.parseType()
|
||||||
p.expectSemi()
|
p.expectSemi()
|
||||||
|
|
||||||
@ -1902,23 +1743,13 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
|
|||||||
defer un(trace(p, "VarSpec"))
|
defer un(trace(p, "VarSpec"))
|
||||||
}
|
}
|
||||||
|
|
||||||
idents := p.parseIdentList(ast.Var)
|
idents := p.parseIdentList()
|
||||||
if p.funcScope == nil {
|
|
||||||
// the scope of a variable outside any function
|
|
||||||
// is the pkgScope
|
|
||||||
p.declIdentList(p.pkgScope, idents)
|
|
||||||
}
|
|
||||||
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 {
|
||||||
p.expect(token.ASSIGN)
|
p.expect(token.ASSIGN)
|
||||||
values = p.parseExprList()
|
values = p.parseExprList()
|
||||||
}
|
}
|
||||||
if p.funcScope != nil {
|
|
||||||
// the scope of a variable inside a function
|
|
||||||
// begins after the the VarSpec
|
|
||||||
p.declIdentList(p.funcScope, idents)
|
|
||||||
}
|
|
||||||
p.expectSemi()
|
p.expectSemi()
|
||||||
|
|
||||||
return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
|
return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
|
||||||
@ -1956,13 +1787,13 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
|
func (p *parser) parseReceiver() *ast.FieldList {
|
||||||
if p.trace {
|
if p.trace {
|
||||||
defer un(trace(p, "Receiver"))
|
defer un(trace(p, "Receiver"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pos := p.pos
|
pos := p.pos
|
||||||
par := p.parseParameters(scope, false)
|
par := p.parseParameters(false)
|
||||||
|
|
||||||
// must have exactly one receiver
|
// must have exactly one receiver
|
||||||
if par.NumFields() != 1 {
|
if par.NumFields() != 1 {
|
||||||
@ -1990,20 +1821,18 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
|
|||||||
|
|
||||||
doc := p.leadComment
|
doc := p.leadComment
|
||||||
pos := p.expect(token.FUNC)
|
pos := p.expect(token.FUNC)
|
||||||
scope := ast.NewScope(p.funcScope)
|
|
||||||
|
|
||||||
var recv *ast.FieldList
|
var recv *ast.FieldList
|
||||||
if p.tok == token.LPAREN {
|
if p.tok == token.LPAREN {
|
||||||
recv = p.parseReceiver(scope)
|
recv = p.parseReceiver()
|
||||||
}
|
}
|
||||||
|
|
||||||
ident := p.parseIdent(ast.Fun)
|
ident := p.parseIdent()
|
||||||
p.declIdent(p.pkgScope, ident) // there are no local function declarations
|
params, results := p.parseSignature()
|
||||||
params, results := p.parseSignature(scope)
|
|
||||||
|
|
||||||
var body *ast.BlockStmt
|
var body *ast.BlockStmt
|
||||||
if p.tok == token.LBRACE {
|
if p.tok == token.LBRACE {
|
||||||
body = p.parseBody(scope)
|
body = p.parseBody()
|
||||||
}
|
}
|
||||||
p.expectSemi()
|
p.expectSemi()
|
||||||
|
|
||||||
@ -2073,10 +1902,9 @@ func (p *parser) parseFile() *ast.File {
|
|||||||
// package clause
|
// package clause
|
||||||
doc := p.leadComment
|
doc := p.leadComment
|
||||||
pos := p.expect(token.PACKAGE)
|
pos := p.expect(token.PACKAGE)
|
||||||
ident := p.parseIdent(ast.Pkg) // package name is in no scope
|
ident := p.parseIdent()
|
||||||
p.expectSemi()
|
p.expectSemi()
|
||||||
|
|
||||||
p.fileScope = ast.NewScope(p.pkgScope)
|
|
||||||
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.
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -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{}{
|
|||||||
|
|
||||||
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{
|
|||||||
|
|
||||||
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) {
|
|||||||
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{}) {
|
|||||||
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 (
|
|||||||
|
|
||||||
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
|
||||||
|
Loading…
Reference in New Issue
Block a user