etc.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  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. package gc // modernc.org/gc/v3
  5. import (
  6. "fmt"
  7. "go/token"
  8. "math"
  9. "os"
  10. "path/filepath"
  11. "runtime"
  12. "sort"
  13. "strconv"
  14. "strings"
  15. "sync"
  16. "github.com/dustin/go-humanize"
  17. )
  18. // The list of tokens.
  19. const (
  20. // Special tokens
  21. ILLEGAL = token.ILLEGAL
  22. EOF = token.EOF
  23. COMMENT = token.COMMENT
  24. // Identifiers and basic type literals
  25. // (these tokens stand for classes of literals)
  26. IDENT = token.IDENT // main
  27. INT = token.INT // 12345
  28. FLOAT = token.FLOAT // 123.45
  29. IMAG = token.IMAG // 123.45i
  30. CHAR = token.CHAR // 'a'
  31. STRING = token.STRING // "abc"
  32. // Operators and delimiters
  33. ADD = token.ADD // +
  34. SUB = token.SUB // -
  35. MUL = token.MUL // *
  36. QUO = token.QUO // /
  37. REM = token.REM // %
  38. AND = token.AND // &
  39. OR = token.OR // |
  40. XOR = token.XOR // ^
  41. SHL = token.SHL // <<
  42. SHR = token.SHR // >>
  43. AND_NOT = token.AND_NOT // &^
  44. ADD_ASSIGN = token.ADD_ASSIGN // +=
  45. SUB_ASSIGN = token.SUB_ASSIGN // -=
  46. MUL_ASSIGN = token.MUL_ASSIGN // *=
  47. QUO_ASSIGN = token.QUO_ASSIGN // /=
  48. REM_ASSIGN = token.REM_ASSIGN // %=
  49. AND_ASSIGN = token.AND_ASSIGN // &=
  50. OR_ASSIGN = token.OR_ASSIGN // |=
  51. XOR_ASSIGN = token.XOR_ASSIGN // ^=
  52. SHL_ASSIGN = token.SHL_ASSIGN // <<=
  53. SHR_ASSIGN = token.SHR_ASSIGN // >>=
  54. AND_NOT_ASSIGN = token.AND_NOT_ASSIGN // &^=
  55. LAND = token.LAND // &&
  56. LOR = token.LOR // ||
  57. ARROW = token.ARROW // <-
  58. INC = token.INC // ++
  59. DEC = token.DEC // --
  60. EQL = token.EQL // ==
  61. LSS = token.LSS // <
  62. GTR = token.GTR // >
  63. ASSIGN = token.ASSIGN // =
  64. NOT = token.NOT // !
  65. NEQ = token.NEQ // !=
  66. LEQ = token.LEQ // <=
  67. GEQ = token.GEQ // >=
  68. DEFINE = token.DEFINE // :=
  69. ELLIPSIS = token.ELLIPSIS // ...
  70. LPAREN = token.LPAREN // (
  71. LBRACK = token.LBRACK // [
  72. LBRACE = token.LBRACE // {
  73. COMMA = token.COMMA // ,
  74. PERIOD = token.PERIOD // .
  75. RPAREN = token.RPAREN // )
  76. RBRACK = token.RBRACK // ]
  77. RBRACE = token.RBRACE // }
  78. SEMICOLON = token.SEMICOLON // ;
  79. COLON = token.COLON // :
  80. // Keywords
  81. BREAK = token.BREAK
  82. CASE = token.CASE
  83. CHAN = token.CHAN
  84. CONST = token.CONST
  85. CONTINUE = token.CONTINUE
  86. DEFAULT = token.DEFAULT
  87. DEFER = token.DEFER
  88. ELSE = token.ELSE
  89. FALLTHROUGH = token.FALLTHROUGH
  90. FOR = token.FOR
  91. FUNC = token.FUNC
  92. GO = token.GO
  93. GOTO = token.GOTO
  94. IF = token.IF
  95. IMPORT = token.IMPORT
  96. INTERFACE = token.INTERFACE
  97. MAP = token.MAP
  98. PACKAGE = token.PACKAGE
  99. RANGE = token.RANGE
  100. RETURN = token.RETURN
  101. SELECT = token.SELECT
  102. STRUCT = token.STRUCT
  103. SWITCH = token.SWITCH
  104. TYPE = token.TYPE
  105. VAR = token.VAR
  106. // additional tokens, handled in an ad-hoc manner
  107. TILDE = token.TILDE
  108. )
  109. var (
  110. trcTODOs bool
  111. extendedErrors bool
  112. )
  113. // origin returns caller's short position, skipping skip frames.
  114. func origin(skip int) string {
  115. pc, fn, fl, _ := runtime.Caller(skip)
  116. f := runtime.FuncForPC(pc)
  117. var fns string
  118. if f != nil {
  119. fns = f.Name()
  120. if x := strings.LastIndex(fns, "."); x > 0 {
  121. fns = fns[x+1:]
  122. }
  123. if strings.HasPrefix(fns, "func") {
  124. num := true
  125. for _, c := range fns[len("func"):] {
  126. if c < '0' || c > '9' {
  127. num = false
  128. break
  129. }
  130. }
  131. if num {
  132. return origin(skip + 2)
  133. }
  134. }
  135. }
  136. return fmt.Sprintf("%s:%d:%s", filepath.Base(fn), fl, fns)
  137. }
  138. // todo prints and returns caller's position and an optional message tagged with TODO. Output goes to stderr.
  139. //
  140. //lint:ignore U1000 whatever
  141. func todo(s string, args ...interface{}) string {
  142. switch {
  143. case s == "":
  144. s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
  145. default:
  146. s = fmt.Sprintf(s, args...)
  147. }
  148. r := fmt.Sprintf("%s\n\tTODO (%s)", origin(2), s)
  149. // fmt.Fprintf(os.Stderr, "%s\n", r)
  150. // os.Stdout.Sync()
  151. return r
  152. }
  153. // trc prints and returns caller's position and an optional message tagged with TRC. Output goes to stderr.
  154. //
  155. //lint:ignore U1000 whatever
  156. func trc(s string, args ...interface{}) string {
  157. switch {
  158. case s == "":
  159. s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
  160. default:
  161. s = fmt.Sprintf(s, args...)
  162. }
  163. r := fmt.Sprintf("%s: TRC (%s)", origin(2), s)
  164. fmt.Fprintf(os.Stderr, "%s\n", r)
  165. os.Stderr.Sync()
  166. return r
  167. }
  168. func extractPos(s string) (p token.Position, ok bool) {
  169. var prefix string
  170. if len(s) > 1 && s[1] == ':' { // c:\foo
  171. prefix = s[:2]
  172. s = s[2:]
  173. }
  174. // "testdata/parser/bug/001.c:1193: ..."
  175. a := strings.Split(s, ":")
  176. // ["testdata/parser/bug/001.c" "1193" "..."]
  177. if len(a) < 2 {
  178. return p, false
  179. }
  180. line, err := strconv.Atoi(a[1])
  181. if err != nil {
  182. return p, false
  183. }
  184. col, err := strconv.Atoi(a[2])
  185. if err != nil {
  186. col = 1
  187. }
  188. return token.Position{Filename: prefix + a[0], Line: line, Column: col}, true
  189. }
  190. // errorf constructs an error value. If extendedErrors is true, the error will
  191. // contain its origin.
  192. func errorf(s string, args ...interface{}) error {
  193. switch {
  194. case s == "":
  195. s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
  196. default:
  197. s = fmt.Sprintf(s, args...)
  198. }
  199. if trcTODOs && strings.HasPrefix(s, "TODO") {
  200. fmt.Fprintf(os.Stderr, "%s (%v)\n", s, origin(2))
  201. os.Stderr.Sync()
  202. }
  203. switch {
  204. case extendedErrors:
  205. return fmt.Errorf("%s (%v: %v: %v)", s, origin(4), origin(3), origin(2))
  206. default:
  207. return fmt.Errorf("%s", s)
  208. }
  209. }
  210. func tokSource(t token.Token) string {
  211. switch t {
  212. case ILLEGAL:
  213. return "ILLEGAL"
  214. case EOF:
  215. return "EOF"
  216. case COMMENT:
  217. return "COMMENT"
  218. case IDENT:
  219. return "IDENT"
  220. case INT:
  221. return "INT"
  222. case FLOAT:
  223. return "FLOAT"
  224. case IMAG:
  225. return "IMAG"
  226. case CHAR:
  227. return "CHAR"
  228. case STRING:
  229. return "STRING"
  230. case ADD:
  231. return "ADD"
  232. case SUB:
  233. return "SUB"
  234. case MUL:
  235. return "MUL"
  236. case QUO:
  237. return "QUO"
  238. case REM:
  239. return "REM"
  240. case AND:
  241. return "AND"
  242. case OR:
  243. return "OR"
  244. case XOR:
  245. return "XOR"
  246. case SHL:
  247. return "SHL"
  248. case SHR:
  249. return "SHR"
  250. case AND_NOT:
  251. return "AND_NOT"
  252. case ADD_ASSIGN:
  253. return "ADD_ASSIGN"
  254. case SUB_ASSIGN:
  255. return "SUB_ASSIGN"
  256. case MUL_ASSIGN:
  257. return "MUL_ASSIGN"
  258. case QUO_ASSIGN:
  259. return "QUO_ASSIGN"
  260. case REM_ASSIGN:
  261. return "REM_ASSIGN"
  262. case AND_ASSIGN:
  263. return "AND_ASSIGN"
  264. case OR_ASSIGN:
  265. return "OR_ASSIGN"
  266. case XOR_ASSIGN:
  267. return "XOR_ASSIGN"
  268. case SHL_ASSIGN:
  269. return "SHL_ASSIGN"
  270. case SHR_ASSIGN:
  271. return "SHR_ASSIGN"
  272. case AND_NOT_ASSIGN:
  273. return "AND_NOT_ASSIGN"
  274. case LAND:
  275. return "LAND"
  276. case LOR:
  277. return "LOR"
  278. case ARROW:
  279. return "ARROW"
  280. case INC:
  281. return "INC"
  282. case DEC:
  283. return "DEC"
  284. case EQL:
  285. return "EQL"
  286. case LSS:
  287. return "LSS"
  288. case GTR:
  289. return "GTR"
  290. case ASSIGN:
  291. return "ASSIGN"
  292. case NOT:
  293. return "NOT"
  294. case NEQ:
  295. return "NEQ"
  296. case LEQ:
  297. return "LEQ"
  298. case GEQ:
  299. return "GEQ"
  300. case DEFINE:
  301. return "DEFINE"
  302. case ELLIPSIS:
  303. return "ELLIPSIS"
  304. case LPAREN:
  305. return "LPAREN"
  306. case LBRACK:
  307. return "LBRACK"
  308. case LBRACE:
  309. return "LBRACE"
  310. case COMMA:
  311. return "COMMA"
  312. case PERIOD:
  313. return "PERIOD"
  314. case RPAREN:
  315. return "RPAREN"
  316. case RBRACK:
  317. return "RBRACK"
  318. case RBRACE:
  319. return "RBRACE"
  320. case SEMICOLON:
  321. return "SEMICOLON"
  322. case COLON:
  323. return "COLON"
  324. case BREAK:
  325. return "BREAK"
  326. case CASE:
  327. return "CASE"
  328. case CHAN:
  329. return "CHAN"
  330. case CONST:
  331. return "CONST"
  332. case CONTINUE:
  333. return "CONTINUE"
  334. case DEFAULT:
  335. return "DEFAULT"
  336. case DEFER:
  337. return "DEFER"
  338. case ELSE:
  339. return "ELSE"
  340. case FALLTHROUGH:
  341. return "FALLTHROUGH"
  342. case FOR:
  343. return "FOR"
  344. case FUNC:
  345. return "FUNC"
  346. case GO:
  347. return "GO"
  348. case GOTO:
  349. return "GOTO"
  350. case IF:
  351. return "IF"
  352. case IMPORT:
  353. return "IMPORT"
  354. case INTERFACE:
  355. return "INTERFACE"
  356. case MAP:
  357. return "MAP"
  358. case PACKAGE:
  359. return "PACKAGE"
  360. case RANGE:
  361. return "RANGE"
  362. case RETURN:
  363. return "RETURN"
  364. case SELECT:
  365. return "SELECT"
  366. case STRUCT:
  367. return "STRUCT"
  368. case SWITCH:
  369. return "SWITCH"
  370. case TYPE:
  371. return "TYPE"
  372. case VAR:
  373. return "VAR"
  374. case TILDE:
  375. return "TILDE"
  376. default:
  377. panic(todo("", int(t), t))
  378. }
  379. }
  380. type data struct {
  381. line int
  382. cases int
  383. cnt int
  384. }
  385. type analyzer struct {
  386. sync.Mutex
  387. m map[int]*data // line: data
  388. }
  389. func newAnalyzer() *analyzer {
  390. return &analyzer{m: map[int]*data{}}
  391. }
  392. func (a *analyzer) record(line, cnt int) {
  393. d := a.m[line]
  394. if d == nil {
  395. d = &data{line: line}
  396. a.m[line] = d
  397. }
  398. d.cases++
  399. d.cnt += cnt
  400. }
  401. func (a *analyzer) merge(b *analyzer) {
  402. a.Lock()
  403. defer a.Unlock()
  404. for k, v := range b.m {
  405. d := a.m[k]
  406. if d == nil {
  407. d = &data{line: k}
  408. a.m[k] = d
  409. }
  410. d.cases += v.cases
  411. d.cnt += v.cnt
  412. }
  413. }
  414. func (a *analyzer) report() string {
  415. var rows []*data
  416. for _, v := range a.m {
  417. rows = append(rows, v)
  418. }
  419. sort.Slice(rows, func(i, j int) bool {
  420. a := rows[i]
  421. b := rows[j]
  422. if a.cases < b.cases {
  423. return true
  424. }
  425. if a.cases > b.cases {
  426. return false
  427. }
  428. // a.cases == b.cases
  429. if a.cnt < b.cnt {
  430. return true
  431. }
  432. if a.cnt > b.cnt {
  433. return false
  434. }
  435. // a.cnt == b.cnt
  436. return a.line < b.line
  437. })
  438. var b strings.Builder
  439. var cases, cnt int
  440. for _, row := range rows {
  441. cases += row.cases
  442. cnt += row.cnt
  443. avg := float64(row.cnt) / float64(row.cases)
  444. fmt.Fprintf(&b, "parser.go:%d:\t%16s %16s %8.1f\n", row.line, h(row.cases), h(row.cnt), avg)
  445. }
  446. avg := float64(cnt) / float64(cases)
  447. fmt.Fprintf(&b, "<total>\t\t%16s %16s %8.1f\n", h(cases), h(cnt), avg)
  448. return b.String()
  449. }
  450. func h(v interface{}) string {
  451. switch x := v.(type) {
  452. case int:
  453. return humanize.Comma(int64(x))
  454. case int32:
  455. return humanize.Comma(int64(x))
  456. case int64:
  457. return humanize.Comma(x)
  458. case uint32:
  459. return humanize.Comma(int64(x))
  460. case uint64:
  461. if x <= math.MaxInt64 {
  462. return humanize.Comma(int64(x))
  463. }
  464. return "-" + humanize.Comma(-int64(x))
  465. }
  466. return fmt.Sprint(v)
  467. }
  468. type parallel struct {
  469. limiter chan struct{}
  470. }
  471. func newParallel() *parallel {
  472. return &parallel{
  473. limiter: make(chan struct{}, runtime.GOMAXPROCS(0)),
  474. }
  475. }
  476. func (p *parallel) throttle(f func()) {
  477. p.limiter <- struct{}{}
  478. defer func() {
  479. <-p.limiter
  480. }()
  481. f()
  482. }
  483. func extraTags(verMajor, verMinor int, goos, goarch string) (r []string) {
  484. // https://github.com/golang/go/commit/eeb7899137cda1c2cd60dab65ff41f627436db5b
  485. //
  486. // In Go 1.17 we added register ABI on AMD64 on Linux/macOS/Windows
  487. // as a GOEXPERIMENT, on by default. In Go 1.18, we commit to always
  488. // enabling register ABI on AMD64.
  489. //
  490. // Now "go build" for AMD64 always have goexperiment.regabi* tags
  491. // set. However, at bootstrapping cmd/dist does not set the tags
  492. // when building go_bootstrap. For this to work, unfortunately, we
  493. // need to hard-code AMD64 to use register ABI in runtime code.
  494. if verMajor == 1 {
  495. switch {
  496. case verMinor == 17:
  497. switch goos {
  498. case "linux", "darwin", "windows":
  499. if goarch == "amd64" {
  500. r = append(r, "goexperiment.regabiargs", "goexperiment.regabiwrappers")
  501. }
  502. }
  503. case verMinor >= 18:
  504. if goarch == "amd64" {
  505. r = append(r, "goexperiment.regabiargs", "goexperiment.regabiwrappers")
  506. }
  507. }
  508. }
  509. return r
  510. }