forked from KurokuLabs/margo
/
parse.go
77 lines (69 loc) · 1.61 KB
/
parse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package goutil
import (
"go/ast"
"go/parser"
"go/scanner"
"go/token"
"io/ioutil"
"margo.sh/mg"
)
const (
ParseFileMode = parser.ParseComments | parser.DeclarationErrors | parser.AllErrors
)
var (
NilPkgName = "_"
NilFset = token.NewFileSet()
NilPkgSrc = "\n\npackage " + NilPkgName + "\n"
NilAstFile, _ = parser.ParseFile(NilFset, "", NilPkgSrc, 0)
NilTokenFile = NilFset.File(NilAstFile.Pos())
)
type ParsedFile struct {
Fset *token.FileSet
AstFile *ast.File
TokenFile *token.File
Error error
ErrorList scanner.ErrorList
}
func ParseFile(mx *mg.Ctx, fn string, src []byte) *ParsedFile {
return ParseFileWithMode(mx, fn, src, ParseFileMode)
}
func ParseFileWithMode(mx *mg.Ctx, fn string, src []byte, mode parser.Mode) *ParsedFile {
if len(src) == 0 {
var err error
if fn != "" {
src, err = ioutil.ReadFile(fn)
}
if len(src) == 0 {
return &ParsedFile{
Fset: NilFset,
AstFile: NilAstFile,
TokenFile: NilTokenFile,
Error: err,
}
}
}
type key struct {
hash string
mode parser.Mode
}
k := key{hash: mg.SrcHash(src), mode: mode}
if pf, ok := mx.Get(k).(*ParsedFile); ok {
return pf
}
_, memo, _ := mx.VFS.Memo(fn)
pf := memo.Read(k, func() interface{} {
pf := &ParsedFile{Fset: token.NewFileSet()}
pf.AstFile, pf.Error = parser.ParseFile(pf.Fset, fn, src, mode)
if pf.AstFile == nil {
pf.AstFile = NilAstFile
}
pf.TokenFile = pf.Fset.File(pf.AstFile.Pos())
if pf.TokenFile == nil {
pf.TokenFile = NilTokenFile
}
pf.ErrorList, _ = pf.Error.(scanner.ErrorList)
return pf
}).(*ParsedFile)
mx.Put(k, pf)
return pf
}