gc.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. // Copyright 2022 The Gc Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:generate stringer -output stringer.go -linecomment -type=Kind,ScopeKind,ChanDir,TypeCheck
  5. package gc // modernc.org/gc/v3
  6. import (
  7. "fmt"
  8. "go/build"
  9. "go/build/constraint"
  10. "go/token"
  11. "io"
  12. "io/fs"
  13. "os"
  14. "path/filepath"
  15. "runtime"
  16. "sort"
  17. "strconv"
  18. "strings"
  19. "sync"
  20. "unicode"
  21. "github.com/hashicorp/golang-lru/v2"
  22. )
  23. var (
  24. trcErrors bool
  25. )
  26. type FileFilter func(cfg *Config, importPath string, matchedFSPaths []string, withTestFiles bool) (pkgFiles []string, err error)
  27. type TypeCheck int
  28. const (
  29. TypeCheckNone TypeCheck = iota
  30. TypeCheckAll
  31. )
  32. type cacheKey struct {
  33. buildTagsKey string
  34. cfg *Config
  35. fsPath string
  36. goarch string
  37. goos string
  38. gopathKey string
  39. goroot string
  40. importPath string
  41. typeCheck TypeCheck
  42. withTestFiles bool
  43. }
  44. type cacheItem struct {
  45. pkg *Package
  46. ch chan struct{}
  47. }
  48. func newCacheItem() *cacheItem { return &cacheItem{ch: make(chan struct{})} }
  49. func (c *cacheItem) set(pkg *Package) {
  50. c.pkg = pkg
  51. close(c.ch)
  52. }
  53. func (c *cacheItem) wait() *Package {
  54. <-c.ch
  55. return c.pkg
  56. }
  57. type Cache struct {
  58. sync.Mutex
  59. lru *lru.TwoQueueCache[cacheKey, *cacheItem]
  60. }
  61. func NewCache(size int) (*Cache, error) {
  62. c, err := lru.New2Q[cacheKey, *cacheItem](size)
  63. if err != nil {
  64. return nil, err
  65. }
  66. return &Cache{lru: c}, nil
  67. }
  68. func MustNewCache(size int) *Cache {
  69. c, err := NewCache(size)
  70. if err != nil {
  71. panic(todo("", err))
  72. }
  73. return c
  74. }
  75. type ConfigOption func(*Config) error
  76. // Config configures NewPackage
  77. //
  78. // Config instances can be shared, they are not mutated once created and
  79. // configured.
  80. type Config struct {
  81. abi *ABI
  82. buildTagMap map[string]bool
  83. buildTags []string
  84. buildTagsKey string // Zero byte separated
  85. builtin *Package
  86. cache *Cache
  87. cmp *Package // Go 1.21
  88. env map[string]string
  89. fs fs.FS
  90. goarch string
  91. gocompiler string // "gc", "gccgo"
  92. goos string
  93. gopath string
  94. gopathKey string // Zero byte separated
  95. goroot string
  96. goversion string
  97. lookup func(rel, importPath, version string) (fsPath string, err error)
  98. parallel *parallel
  99. searchGoPaths []string
  100. searchGoroot []string
  101. int Type // Set by NewConfig
  102. uint Type // Set by NewConfig
  103. arch32bit bool
  104. configured bool
  105. }
  106. // NewConfig returns a newly created config or an error, if any.
  107. func NewConfig(opts ...ConfigOption) (r *Config, err error) {
  108. r = &Config{
  109. buildTagMap: map[string]bool{},
  110. env: map[string]string{},
  111. parallel: newParallel(),
  112. }
  113. defer func() {
  114. if r != nil {
  115. r.configured = true
  116. }
  117. }()
  118. r.lookup = r.DefaultLookup
  119. ctx := build.Default
  120. r.goos = r.getenv("GOOS", ctx.GOOS)
  121. r.goarch = r.getenv("GOARCH", ctx.GOARCH)
  122. r.goroot = r.getenv("GOROOT", ctx.GOROOT)
  123. r.gopath = r.getenv("GOPATH", ctx.GOPATH)
  124. r.buildTags = append(r.buildTags, r.goos, r.goarch)
  125. r.gocompiler = runtime.Compiler
  126. for _, opt := range opts {
  127. if err := opt(r); err != nil {
  128. return nil, err
  129. }
  130. }
  131. if r.abi, err = NewABI(r.goos, r.goarch); err != nil {
  132. return nil, err
  133. }
  134. switch r.goarch {
  135. case "386", "arm":
  136. r.arch32bit = true
  137. }
  138. // During a particular build, the following build tags are satisfied:
  139. //
  140. // the target operating system, as spelled by runtime.GOOS, set with the GOOS environment variable.
  141. // the target architecture, as spelled by runtime.GOARCH, set with the GOARCH environment variable.
  142. // "unix", if GOOS is a Unix or Unix-like system.
  143. // the compiler being used, either "gc" or "gccgo"
  144. // "cgo", if the cgo command is supported (see CGO_ENABLED in 'go help environment').
  145. // a term for each Go major release, through the current version: "go1.1" from Go version 1.1 onward, "go1.12" from Go 1.12, and so on.
  146. // any additional tags given by the -tags flag (see 'go help build').
  147. // There are no separate build tags for beta or minor releases.
  148. if r.goversion == "" {
  149. r.goversion = runtime.Version()
  150. }
  151. if !strings.HasPrefix(r.goversion, "go") || !strings.Contains(r.goversion, ".") {
  152. return nil, fmt.Errorf("cannot parse Go version: %s", r.goversion)
  153. }
  154. ver := strings.SplitN(r.goversion[len("go"):], ".", 2)
  155. verMajor, err := strconv.Atoi(ver[0])
  156. if err != nil {
  157. return nil, fmt.Errorf("cannot parse Go version %s: %v", r.goversion, err)
  158. }
  159. if verMajor != 1 {
  160. return nil, fmt.Errorf("unsupported Go version: %s", r.goversion)
  161. }
  162. switch x, x2 := strings.IndexByte(ver[1], '.'), strings.Index(ver[1], "rc"); {
  163. case x >= 0:
  164. ver[1] = ver[1][:x]
  165. case x2 >= 0:
  166. ver[1] = ver[1][:x2]
  167. }
  168. verMinor, err := strconv.Atoi(ver[1])
  169. if err != nil {
  170. return nil, fmt.Errorf("cannot parse Go version %s: %v", r.goversion, err)
  171. }
  172. for i := 1; i <= verMinor; i++ {
  173. r.buildTags = append(r.buildTags, fmt.Sprintf("go%d.%d", verMajor, i))
  174. }
  175. r.buildTags = append(r.buildTags, r.gocompiler)
  176. r.buildTags = append(r.buildTags, extraTags(verMajor, verMinor, r.goos, r.goarch)...)
  177. if r.getenv("CGO_ENABLED", "1") == "1" {
  178. r.buildTags = append(r.buildTags, "cgo")
  179. }
  180. for i, v := range r.buildTags {
  181. tag := strings.TrimSpace(v)
  182. r.buildTags[i] = tag
  183. r.buildTagMap[tag] = true
  184. }
  185. sort.Strings(r.buildTags)
  186. r.buildTagsKey = strings.Join(r.buildTags, "\x00")
  187. r.searchGoroot = []string{filepath.Join(r.goroot, "src")}
  188. r.searchGoPaths = filepath.SplitList(r.gopath)
  189. r.gopathKey = strings.Join(r.searchGoPaths, "\x00")
  190. for i, v := range r.searchGoPaths {
  191. r.searchGoPaths[i] = filepath.Join(v, "src")
  192. }
  193. switch r.cmp, err = r.NewPackage("", "cmp", "", nil, false, TypeCheckNone); {
  194. case err != nil:
  195. r.cmp = nil
  196. default:
  197. //TODO r.cmp.Scope.kind = UniverseScope
  198. }
  199. if r.builtin, err = r.NewPackage("", "builtin", "", nil, false, TypeCheckNone); err != nil {
  200. return nil, err
  201. }
  202. r.builtin.Scope.kind = UniverseScope
  203. if err := r.builtin.check(newCtx(r)); err != nil {
  204. return nil, err
  205. }
  206. return r, nil
  207. }
  208. func (c *Config) universe() *Scope {
  209. if c.builtin != nil {
  210. return c.builtin.Scope
  211. }
  212. return nil
  213. }
  214. func (c *Config) stat(name string) (fs.FileInfo, error) {
  215. if c.fs == nil {
  216. return os.Stat(name)
  217. }
  218. name = filepath.ToSlash(name)
  219. if x, ok := c.fs.(fs.StatFS); ok {
  220. return x.Stat(name)
  221. }
  222. f, err := c.fs.Open(name)
  223. if err != nil {
  224. return nil, err
  225. }
  226. defer f.Close()
  227. return f.Stat()
  228. }
  229. func (c *Config) open(name string) (fs.File, error) {
  230. if c.fs == nil {
  231. return os.Open(name)
  232. }
  233. name = filepath.ToSlash(name)
  234. return c.fs.Open(name)
  235. }
  236. func (c *Config) glob(pattern string) (matches []string, err error) {
  237. if c.fs == nil {
  238. return filepath.Glob(pattern)
  239. }
  240. pattern = filepath.ToSlash(pattern)
  241. return fs.Glob(c.fs, pattern)
  242. }
  243. func (c *Config) checkConstraints(pos token.Position, sep string) (r bool) {
  244. if !strings.Contains(sep, "//go:build") && !strings.Contains(sep, "+build") {
  245. return true
  246. }
  247. // defer func() { trc("", r) }()
  248. lines := strings.Split(sep, "\n")
  249. var build, plusBuild []string
  250. for i, line := range lines {
  251. if constraint.IsGoBuild(line) && i < len(lines)-1 && lines[i+1] == "" {
  252. build = append(build, line)
  253. }
  254. if constraint.IsPlusBuild(line) {
  255. plusBuild = append(plusBuild, line)
  256. }
  257. }
  258. switch len(build) {
  259. case 0:
  260. // ok
  261. case 1:
  262. expr, err := constraint.Parse(build[0])
  263. if err != nil {
  264. return true
  265. }
  266. return expr.Eval(func(tag string) (r bool) {
  267. // defer func() { trc("%q: %v", tag, r) }()
  268. switch tag {
  269. case "unix":
  270. return unixOS[c.goos]
  271. default:
  272. return c.buildTagMap[tag]
  273. }
  274. })
  275. default:
  276. panic(todo("%v: %q", pos, build))
  277. }
  278. for _, line := range plusBuild {
  279. expr, err := constraint.Parse(line)
  280. if err != nil {
  281. return true
  282. }
  283. if !expr.Eval(func(tag string) (r bool) {
  284. // defer func() { trc("%q: %v", tag, r) }()
  285. switch tag {
  286. case "unix":
  287. return unixOS[c.goos]
  288. default:
  289. return c.buildTagMap[tag]
  290. }
  291. }) {
  292. return false
  293. }
  294. }
  295. return true
  296. }
  297. // Default lookup translates import paths, possibly relative to rel, to file system paths.
  298. func (c *Config) DefaultLookup(rel, importPath, version string) (fsPath string, err error) {
  299. if importPath == "" {
  300. return "", fmt.Errorf("import path cannot be emtpy")
  301. }
  302. // Implementation restriction: A compiler may restrict ImportPaths to non-empty
  303. // strings using only characters belonging to Unicode's L, M, N, P, and S
  304. // general categories (the Graphic characters without spaces) and may also
  305. // exclude the characters !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement
  306. // character U+FFFD.
  307. if strings.ContainsAny(importPath, "!\"#$%&'()*,:;<=>?[\\]^`{|}\ufffd") {
  308. return "", fmt.Errorf("invalid import path: %s", importPath)
  309. }
  310. for _, r := range importPath {
  311. if !unicode.Is(unicode.L, r) &&
  312. !unicode.Is(unicode.M, r) &&
  313. !unicode.Is(unicode.N, r) &&
  314. !unicode.Is(unicode.P, r) &&
  315. !unicode.Is(unicode.S, r) {
  316. return "", fmt.Errorf("invalid import path: %s", importPath)
  317. }
  318. }
  319. var search []string
  320. ip0 := importPath
  321. switch slash := strings.IndexByte(importPath, '/'); {
  322. case strings.HasPrefix(importPath, "./"):
  323. if rel != "" {
  324. panic(todo(""))
  325. }
  326. return "", fmt.Errorf("invalid import path: %s", importPath)
  327. case strings.HasPrefix(importPath, "/"):
  328. return importPath, nil
  329. case slash > 0:
  330. ip0 = importPath[:slash]
  331. default:
  332. ip0 = importPath
  333. }
  334. if ip0 != "" {
  335. switch {
  336. case strings.Contains(ip0, "."):
  337. search = c.searchGoPaths
  338. default:
  339. search = c.searchGoroot
  340. }
  341. }
  342. for _, v := range search {
  343. fsPath = filepath.Join(v, importPath)
  344. dir, err := c.open(fsPath)
  345. if err != nil {
  346. continue
  347. }
  348. fi, err := dir.Stat()
  349. dir.Close()
  350. if err != nil {
  351. continue
  352. }
  353. if fi.IsDir() {
  354. return fsPath, nil
  355. }
  356. }
  357. return "", fmt.Errorf("cannot find package %s, searched %v", importPath, search)
  358. }
  359. func (c *Config) getenv(nm, deflt string) (r string) {
  360. if r = c.env[nm]; r != "" {
  361. return r
  362. }
  363. if r = os.Getenv(nm); r != "" {
  364. return r
  365. }
  366. return deflt
  367. }
  368. func DefaultFileFilter(cfg *Config, importPath string, matchedFSPaths []string, withTestFiles bool) (pkgFiles []string, err error) {
  369. w := 0
  370. for _, v := range matchedFSPaths {
  371. base := filepath.Base(v)
  372. base = base[:len(base)-len(filepath.Ext(base))]
  373. const testSuffix = "_test"
  374. if strings.HasSuffix(base, testSuffix) {
  375. if !withTestFiles {
  376. continue
  377. }
  378. base = base[:len(base)-len(testSuffix)]
  379. }
  380. if x := strings.LastIndexByte(base, '_'); x > 0 {
  381. last := base[x+1:]
  382. base = base[:x]
  383. var prevLast string
  384. if x := strings.LastIndexByte(base, '_'); x > 0 {
  385. prevLast = base[x+1:]
  386. }
  387. if last != "" && prevLast != "" {
  388. // *_GOOS_GOARCH
  389. if knownOS[prevLast] && prevLast != cfg.goos {
  390. continue
  391. }
  392. if knownArch[last] && last != cfg.goarch {
  393. continue
  394. }
  395. }
  396. if last != "" {
  397. // *_GOOS or *_GOARCH
  398. if knownOS[last] && last != cfg.goos {
  399. continue
  400. }
  401. if knownArch[last] && last != cfg.goarch {
  402. continue
  403. }
  404. }
  405. }
  406. matchedFSPaths[w] = v
  407. w++
  408. }
  409. return matchedFSPaths[:w], nil
  410. }
  411. // ConfigBuildTags configures build tags.
  412. func ConfigBuildTags(tags []string) ConfigOption {
  413. return func(cfg *Config) error {
  414. if cfg.configured {
  415. return fmt.Errorf("ConfigBuildTags: Config instance already configured")
  416. }
  417. cfg.buildTags = append(cfg.buildTags, tags...)
  418. return nil
  419. }
  420. }
  421. // ConfigEnviron configures environment variables.
  422. func ConfigEnviron(env []string) ConfigOption {
  423. return func(cfg *Config) error {
  424. if cfg.configured {
  425. return fmt.Errorf("ConfigEnviron: Config instance already configured")
  426. }
  427. for _, v := range env {
  428. switch x := strings.IndexByte(v, '='); {
  429. case x < 0:
  430. cfg.env[v] = ""
  431. default:
  432. cfg.env[v[:x]] = v[x+1:]
  433. }
  434. }
  435. return nil
  436. }
  437. }
  438. // ConfigFS configures a file system used for opening Go source files. If not
  439. // explicitly configured, a default os.DirFS("/") is used on Unix-like
  440. // operating systems. On Windows it will be rooted on the volume where
  441. // runtime.GOROOT() is.
  442. func ConfigFS(fs fs.FS) ConfigOption {
  443. return func(cfg *Config) error {
  444. if cfg.configured {
  445. return fmt.Errorf("ConfigFS: Config instance already configured")
  446. }
  447. cfg.fs = fs
  448. return nil
  449. }
  450. }
  451. // ConfigLookup configures a lookup function.
  452. func ConfigLookup(f func(dir, importPath, version string) (fsPath string, err error)) ConfigOption {
  453. return func(cfg *Config) error {
  454. if cfg.configured {
  455. return fmt.Errorf("ConfigLookup: Config instance already configured")
  456. }
  457. cfg.lookup = f
  458. return nil
  459. }
  460. }
  461. // ConfigCache configures a cache.
  462. func ConfigCache(c *Cache) ConfigOption {
  463. return func(cfg *Config) error {
  464. if cfg.configured {
  465. return fmt.Errorf("ConfigCache: Config instance already configured")
  466. }
  467. cfg.cache = c
  468. return nil
  469. }
  470. }
  471. type importGuard struct {
  472. m map[string]struct{}
  473. stack []string
  474. }
  475. func newImportGuard() *importGuard { return &importGuard{m: map[string]struct{}{}} }
  476. // Package represents a Go package. The instance must not be mutated.
  477. type Package struct {
  478. AST map[string]*AST // AST maps fsPaths of individual files to their respective ASTs
  479. FSPath string
  480. GoFiles []fs.FileInfo
  481. ImportPath string
  482. InvalidGoFiles map[string]error // errors for particular files, if any
  483. Name Token
  484. Scope *Scope // Package scope.
  485. Version string
  486. cfg *Config
  487. guard *importGuard
  488. mu sync.Mutex
  489. typeCheck TypeCheck
  490. isUnsafe bool // ImportPath == "usnafe"
  491. // isChecked bool
  492. }
  493. // NewPackage returns a Package, possibly cached, for importPath@version or an
  494. // error, if any. The fileFilter argument can be nil, in such case
  495. // DefaultFileFilter is used, which ignores Files with suffix _test.go unless
  496. // withTestFiles is true.
  497. //
  498. // NewPackage is safe for concurrent use by multiple goroutines.
  499. func (c *Config) NewPackage(dir, importPath, version string, fileFilter FileFilter, withTestFiles bool, typeCheck TypeCheck) (pkg *Package, err error) {
  500. return c.newPackage(dir, importPath, version, fileFilter, withTestFiles, typeCheck, newImportGuard())
  501. }
  502. func (c *Config) newPackage(dir, importPath, version string, fileFilter FileFilter, withTestFiles bool, typeCheck TypeCheck, guard *importGuard) (pkg *Package, err error) {
  503. if _, ok := guard.m[importPath]; ok {
  504. return nil, fmt.Errorf("import cycle %v", guard.stack)
  505. }
  506. guard.stack = append(guard.stack, importPath)
  507. fsPath, err := c.lookup(dir, importPath, version)
  508. if err != nil {
  509. return nil, fmt.Errorf("lookup %s: %v", importPath, err)
  510. }
  511. pat := filepath.Join(fsPath, "*.go")
  512. matches, err := c.glob(pat)
  513. if err != nil {
  514. return nil, fmt.Errorf("glob %s: %v", pat, err)
  515. }
  516. if len(matches) == 0 {
  517. return nil, fmt.Errorf("no Go files in %s", fsPath)
  518. }
  519. if fileFilter == nil {
  520. fileFilter = DefaultFileFilter
  521. }
  522. if matches, err = fileFilter(c, importPath, matches, withTestFiles); err != nil {
  523. return nil, fmt.Errorf("matching Go files in %s: %v", fsPath, err)
  524. }
  525. var k cacheKey
  526. if c.cache != nil {
  527. k = cacheKey{
  528. buildTagsKey: c.buildTagsKey,
  529. cfg: c,
  530. fsPath: fsPath,
  531. goarch: c.goarch,
  532. goos: c.goos,
  533. gopathKey: c.gopathKey,
  534. goroot: c.goroot,
  535. importPath: importPath,
  536. typeCheck: typeCheck,
  537. withTestFiles: withTestFiles,
  538. }
  539. c.cache.Lock() // ---------------------------------------- lock
  540. item, ok := c.cache.lru.Get(k)
  541. if ok {
  542. c.cache.Unlock() // ---------------------------- unlock
  543. if pkg = item.wait(); pkg != nil && pkg.matches(&k, matches) {
  544. return pkg, nil
  545. }
  546. }
  547. item = newCacheItem()
  548. c.cache.lru.Add(k, item)
  549. c.cache.Unlock() // ------------------------------------ unlock
  550. defer func() {
  551. if pkg != nil && err == nil {
  552. item.set(pkg)
  553. }
  554. }()
  555. }
  556. r := &Package{
  557. AST: map[string]*AST{},
  558. FSPath: fsPath,
  559. ImportPath: importPath,
  560. Scope: newScope(c.universe(), PackageScope),
  561. Version: version,
  562. cfg: c,
  563. guard: guard,
  564. isUnsafe: importPath == "unsafe",
  565. typeCheck: typeCheck,
  566. }
  567. defer func() { r.guard = nil }()
  568. sort.Strings(matches)
  569. defer func() {
  570. sort.Slice(r.GoFiles, func(i, j int) bool { return r.GoFiles[i].Name() < r.GoFiles[j].Name() })
  571. if err != nil || len(r.InvalidGoFiles) != 0 || typeCheck == TypeCheckNone {
  572. return
  573. }
  574. //TODO err = r.check(newCtx(c))
  575. }()
  576. c.parallel.throttle(func() {
  577. for _, path := range matches {
  578. if err = c.newPackageFile(r, path); err != nil {
  579. return
  580. }
  581. }
  582. })
  583. return r, err
  584. }
  585. func (c *Config) newPackageFile(pkg *Package, path string) (err error) {
  586. f, err := c.open(path)
  587. if err != nil {
  588. return fmt.Errorf("opening file %q: %v", path, err)
  589. }
  590. defer func() {
  591. f.Close()
  592. if err != nil {
  593. if pkg.InvalidGoFiles == nil {
  594. pkg.InvalidGoFiles = map[string]error{}
  595. }
  596. pkg.InvalidGoFiles[path] = err
  597. }
  598. }()
  599. var fi fs.FileInfo
  600. if fi, err = f.Stat(); err != nil {
  601. return fmt.Errorf("stat %s: %v", path, err)
  602. }
  603. if !fi.Mode().IsRegular() {
  604. return nil
  605. }
  606. var b []byte
  607. if b, err = io.ReadAll(f); err != nil {
  608. return fmt.Errorf("reading %s: %v", path, err)
  609. }
  610. p := newParser(pkg.Scope, path, b, false)
  611. if p.peek(0) == PACKAGE {
  612. tok := Token{p.s.source, p.s.toks[p.ix].ch, int32(p.ix)}
  613. if !c.checkConstraints(tok.Position(), tok.Sep()) {
  614. return nil
  615. }
  616. }
  617. pkg.GoFiles = append(pkg.GoFiles, fi)
  618. var ast *AST
  619. if ast, err = p.parse(); err != nil {
  620. return nil
  621. }
  622. pkg.AST[path] = ast
  623. return nil
  624. }
  625. func (p *Package) matches(k *cacheKey, matches []string) bool {
  626. matched := map[string]struct{}{}
  627. for _, match := range matches {
  628. matched[match] = struct{}{}
  629. }
  630. for _, cachedInfo := range p.GoFiles {
  631. name := cachedInfo.Name()
  632. path := filepath.Join(p.FSPath, name)
  633. if _, ok := matched[path]; !ok {
  634. return false
  635. }
  636. info, err := k.cfg.stat(path)
  637. if err != nil {
  638. return false
  639. }
  640. if info.IsDir() ||
  641. info.Size() != cachedInfo.Size() ||
  642. info.ModTime().After(cachedInfo.ModTime()) ||
  643. info.Mode() != cachedInfo.Mode() {
  644. return false
  645. }
  646. }
  647. return true
  648. }
  649. // ParseFile parses 'b', assuming it comes from 'path' and returns an AST or error, if any.
  650. func ParseFile(path string, b []byte) (*AST, error) {
  651. return newParser(newScope(nil, PackageScope), path, b, false).parse()
  652. }