3B.4 构造语法树
3.4.1 解析入口
func LoadPackage(filenames []string) {
mode := syntax.CheckBranches
if base.Flag.G != 0 {
mode |= syntax.AllowGenerics // 如果给编译器传递了 -G 这个参数,则可接受泛型语法。通过 go build -gcflags "-G=3" 来传递
}
// Limit the number of simultaneously open files.
sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10) // 控制解析的并发数量
noders := make([]*noder, len(filenames))
for i, filename := range filenames {
p := noder{
err: make(chan syntax.Error),
trackScopes: base.Flag.Dwarf,
}
noders[i] = &p
filename := filename
go func() {
sem <- struct{}{}
defer func() { <-sem }()
defer close(p.err) // 关闭 error channel
fbase := syntax.NewFileBase(filename)
f, err := os.Open(filename)
if err != nil {
p.error(syntax.Error{Msg: err.Error()})
return
}
defer f.Close()
p.file, _ = syntax.Parse(fbase, f, p.error, p.pragma, mode) // 语法解析入口
}()
}
var lines uint
for _, p := range noders {
for e := range p.err { // 错误检查,p.err 是 channel, 只有当该文件解析完成后才会关闭,所以这里也实现了对上面异步、并发解析文件的同步
p.errorAt(e.Pos, "%s", e.Msg)
}
if p.file == nil {
base.ErrorExit()
}
lines += p.file.EOF.Line()
}
base.Timer.AddEvent(int64(lines), "lines")
// 忽略后续类型检查的代码
}3.4.2 初始化
3.4.3 解析过程
最后更新于