parse.y 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. // BUILD file parser.
  2. // This is a yacc grammar. Its lexer is in lex.go.
  3. //
  4. // For a good introduction to writing yacc grammars, see
  5. // Kernighan and Pike's book The Unix Programming Environment.
  6. //
  7. // The definitive yacc manual is
  8. // Stephen C. Johnson and Ravi Sethi, "Yacc: A Parser Generator",
  9. // online at http://plan9.bell-labs.com/sys/doc/yacc.pdf.
  10. %{
  11. package build
  12. %}
  13. // The generated parser puts these fields in a struct named yySymType.
  14. // (The name %union is historical, but it is inaccurate for Go.)
  15. %union {
  16. // input tokens
  17. tok string // raw input syntax
  18. str string // decoding of quoted string
  19. pos Position // position of token
  20. triple bool // was string triple quoted?
  21. // partial syntax trees
  22. expr Expr
  23. exprs []Expr
  24. string *StringExpr
  25. strings []*StringExpr
  26. ifstmt *IfStmt
  27. loadarg *struct{from Ident; to Ident}
  28. loadargs []*struct{from Ident; to Ident}
  29. // supporting information
  30. comma Position // position of trailing comma in list, if present
  31. lastStmt Expr // most recent rule, to attach line comments to
  32. }
  33. // These declarations set the type for a $ reference ($$, $1, $2, ...)
  34. // based on the kind of symbol it refers to. Other fields can be referred
  35. // to explicitly, as in $<tok>1.
  36. //
  37. // %token is for input tokens generated by the lexer.
  38. // %type is for higher-level grammar rules defined here.
  39. //
  40. // It is possible to put multiple tokens per line, but it is easier to
  41. // keep ordered using a sparser one-per-line list.
  42. %token <pos> '%'
  43. %token <pos> '('
  44. %token <pos> ')'
  45. %token <pos> '*'
  46. %token <pos> '+'
  47. %token <pos> ','
  48. %token <pos> '-'
  49. %token <pos> '.'
  50. %token <pos> '/'
  51. %token <pos> ':'
  52. %token <pos> '<'
  53. %token <pos> '='
  54. %token <pos> '>'
  55. %token <pos> '['
  56. %token <pos> ']'
  57. %token <pos> '{'
  58. %token <pos> '}'
  59. %token <pos> '|'
  60. %token <pos> '&'
  61. %token <pos> '^'
  62. %token <pos> '~'
  63. // By convention, yacc token names are all caps.
  64. // However, we do not want to export them from the Go package
  65. // we are creating, so prefix them all with underscores.
  66. %token <pos> _AUGM // augmented assignment
  67. %token <pos> _AND // keyword and
  68. %token <pos> _COMMENT // top-level # comment
  69. %token <pos> _EOF // end of file
  70. %token <pos> _EQ // operator ==
  71. %token <pos> _FOR // keyword for
  72. %token <pos> _GE // operator >=
  73. %token <pos> _IDENT // non-keyword identifier
  74. %token <pos> _NUMBER // number
  75. %token <pos> _IF // keyword if
  76. %token <pos> _ELSE // keyword else
  77. %token <pos> _ELIF // keyword elif
  78. %token <pos> _IN // keyword in
  79. %token <pos> _IS // keyword is
  80. %token <pos> _LAMBDA // keyword lambda
  81. %token <pos> _LOAD // keyword load
  82. %token <pos> _LE // operator <=
  83. %token <pos> _NE // operator !=
  84. %token <pos> _STAR_STAR // operator **
  85. %token <pos> _INT_DIV // operator //
  86. %token <pos> _BIT_LSH // bitwise operator <<
  87. %token <pos> _BIT_RSH // bitwise operator >>
  88. %token <pos> _NOT // keyword not
  89. %token <pos> _OR // keyword or
  90. %token <pos> _STRING // quoted string
  91. %token <pos> _DEF // keyword def
  92. %token <pos> _RETURN // keyword return
  93. %token <pos> _PASS // keyword pass
  94. %token <pos> _BREAK // keyword break
  95. %token <pos> _CONTINUE // keyword continue
  96. %token <pos> _INDENT // indentation
  97. %token <pos> _UNINDENT // unindentation
  98. %type <pos> comma_opt
  99. %type <expr> argument
  100. %type <exprs> arguments
  101. %type <exprs> arguments_opt
  102. %type <expr> parameter
  103. %type <exprs> parameters
  104. %type <exprs> parameters_opt
  105. %type <expr> test
  106. %type <expr> test_opt
  107. %type <exprs> tests_opt
  108. %type <expr> primary_expr
  109. %type <expr> expr
  110. %type <expr> expr_opt
  111. %type <exprs> tests
  112. %type <exprs> exprs
  113. %type <exprs> exprs_opt
  114. %type <expr> loop_vars
  115. %type <expr> for_clause
  116. %type <exprs> for_clause_with_if_clauses_opt
  117. %type <exprs> for_clauses_with_if_clauses_opt
  118. %type <expr> ident
  119. %type <expr> number
  120. %type <exprs> stmts
  121. %type <exprs> stmt // a simple_stmt or a for/if/def block
  122. %type <expr> block_stmt // a single for/if/def statement
  123. %type <ifstmt> if_else_block // a complete if-elif-else block
  124. %type <ifstmt> if_chain // an elif-elif-else chain
  125. %type <pos> elif // `elif` or `else if` token(s)
  126. %type <exprs> simple_stmt // One or many small_stmts on one line, e.g. 'a = f(x); return str(a)'
  127. %type <expr> small_stmt // A single statement, e.g. 'a = f(x)'
  128. %type <exprs> small_stmts_continuation // A sequence of `';' small_stmt`
  129. %type <expr> keyvalue
  130. %type <exprs> keyvalues
  131. %type <exprs> keyvalues_no_comma
  132. %type <string> string
  133. %type <strings> strings
  134. %type <exprs> suite
  135. %type <exprs> comments
  136. %type <loadarg> load_argument
  137. %type <loadargs> load_arguments
  138. // Operator precedence.
  139. // Operators listed lower in the table bind tighter.
  140. // We tag rules with this fake, low precedence to indicate
  141. // that when the rule is involved in a shift/reduce
  142. // conflict, we prefer that the parser shift (try for a longer parse).
  143. // Shifting is the default resolution anyway, but stating it explicitly
  144. // silences yacc's warning for that specific case.
  145. %left ShiftInstead
  146. %left '\n'
  147. %left _ASSERT
  148. // '=' and augmented assignments have the lowest precedence
  149. // e.g. "x = a if c > 0 else 'bar'"
  150. // followed by
  151. // 'if' and 'else' which have lower precedence than all other operators.
  152. // e.g. "a, b if c > 0 else 'foo'" is either a tuple of (a,b) or 'foo'
  153. // and not a tuple of "(a, (b if ... ))"
  154. %left '=' _AUGM
  155. %left _IF _ELSE _ELIF
  156. %left ','
  157. %left ':'
  158. %left _IS
  159. %left _OR
  160. %left _AND
  161. %left '<' '>' _EQ _NE _LE _GE _NOT _IN
  162. %left '|'
  163. %left '^'
  164. %left '&'
  165. %left _BIT_LSH _BIT_RSH
  166. %left '+' '-'
  167. %left '*' '/' '%' _INT_DIV
  168. %left '.' '[' '('
  169. %right _UNARY
  170. %left _STRING
  171. %%
  172. // Grammar rules.
  173. //
  174. // A note on names: if foo is a rule, then foos is a sequence of foos
  175. // (with interleaved commas or other syntax as appropriate)
  176. // and foo_opt is an optional foo.
  177. file:
  178. stmts _EOF
  179. {
  180. yylex.(*input).file = &File{Stmt: $1}
  181. return 0
  182. }
  183. suite:
  184. '\n' comments _INDENT stmts _UNINDENT
  185. {
  186. statements := $4
  187. if $2 != nil {
  188. // $2 can only contain *CommentBlock objects, each of them contains a non-empty After slice
  189. cb := $2[len($2)-1].(*CommentBlock)
  190. // $4 can't be empty and can't start with a comment
  191. stmt := $4[0]
  192. start, _ := stmt.Span()
  193. if start.Line - cb.After[len(cb.After)-1].Start.Line == 1 {
  194. // The first statement of $4 starts on the next line after the last comment of $2.
  195. // Attach the last comment to the first statement
  196. stmt.Comment().Before = cb.After
  197. $2 = $2[:len($2)-1]
  198. }
  199. statements = append($2, $4...)
  200. }
  201. $$ = statements
  202. $<lastStmt>$ = $<lastStmt>4
  203. }
  204. | simple_stmt linebreaks_opt
  205. {
  206. $$ = $1
  207. }
  208. linebreaks_opt:
  209. | linebreaks_opt '\n'
  210. comments:
  211. {
  212. $$ = nil
  213. $<lastStmt>$ = nil
  214. }
  215. | comments _COMMENT '\n'
  216. {
  217. $$ = $1
  218. $<lastStmt>$ = $<lastStmt>1
  219. if $<lastStmt>$ == nil {
  220. cb := &CommentBlock{Start: $2}
  221. $$ = append($$, cb)
  222. $<lastStmt>$ = cb
  223. }
  224. com := $<lastStmt>$.Comment()
  225. com.After = append(com.After, Comment{Start: $2, Token: $<tok>2})
  226. }
  227. | comments '\n'
  228. {
  229. $$ = $1
  230. $<lastStmt>$ = nil
  231. }
  232. stmts:
  233. {
  234. $$ = nil
  235. $<lastStmt>$ = nil
  236. }
  237. | stmts stmt
  238. {
  239. // If this statement follows a comment block,
  240. // attach the comments to the statement.
  241. if cb, ok := $<lastStmt>1.(*CommentBlock); ok {
  242. $$ = append($1[:len($1)-1], $2...)
  243. $2[0].Comment().Before = cb.After
  244. $<lastStmt>$ = $<lastStmt>2
  245. break
  246. }
  247. // Otherwise add to list.
  248. $$ = append($1, $2...)
  249. $<lastStmt>$ = $<lastStmt>2
  250. // Consider this input:
  251. //
  252. // foo()
  253. // # bar
  254. // baz()
  255. //
  256. // If we've just parsed baz(), the # bar is attached to
  257. // foo() as an After comment. Make it a Before comment
  258. // for baz() instead.
  259. if x := $<lastStmt>1; x != nil {
  260. com := x.Comment()
  261. // stmt is never empty
  262. $2[0].Comment().Before = com.After
  263. com.After = nil
  264. }
  265. }
  266. | stmts '\n'
  267. {
  268. // Blank line; sever last rule from future comments.
  269. $$ = $1
  270. $<lastStmt>$ = nil
  271. }
  272. | stmts _COMMENT '\n'
  273. {
  274. $$ = $1
  275. $<lastStmt>$ = $<lastStmt>1
  276. if $<lastStmt>$ == nil {
  277. cb := &CommentBlock{Start: $2}
  278. $$ = append($$, cb)
  279. $<lastStmt>$ = cb
  280. }
  281. com := $<lastStmt>$.Comment()
  282. com.After = append(com.After, Comment{Start: $2, Token: $<tok>2})
  283. }
  284. stmt:
  285. simple_stmt
  286. {
  287. $$ = $1
  288. $<lastStmt>$ = $1[len($1)-1]
  289. }
  290. | block_stmt
  291. {
  292. $$ = []Expr{$1}
  293. $<lastStmt>$ = $1
  294. if cbs := extractTrailingComments($1); len(cbs) > 0 {
  295. $$ = append($$, cbs...)
  296. $<lastStmt>$ = cbs[len(cbs)-1]
  297. if $<lastStmt>1 == nil {
  298. $<lastStmt>$ = nil
  299. }
  300. }
  301. }
  302. block_stmt:
  303. _DEF _IDENT '(' parameters_opt ')' ':' suite
  304. {
  305. $$ = &DefStmt{
  306. Function: Function{
  307. StartPos: $1,
  308. Params: $4,
  309. Body: $7,
  310. },
  311. Name: $<tok>2,
  312. ColonPos: $6,
  313. ForceCompact: forceCompact($3, $4, $5),
  314. ForceMultiLine: forceMultiLine($3, $4, $5),
  315. }
  316. $<lastStmt>$ = $<lastStmt>7
  317. }
  318. | _FOR loop_vars _IN expr ':' suite
  319. {
  320. $$ = &ForStmt{
  321. For: $1,
  322. Vars: $2,
  323. X: $4,
  324. Body: $6,
  325. }
  326. $<lastStmt>$ = $<lastStmt>6
  327. }
  328. | if_else_block
  329. {
  330. $$ = $1
  331. $<lastStmt>$ = $<lastStmt>1
  332. }
  333. // One or several if-elif-elif statements
  334. if_chain:
  335. _IF expr ':' suite
  336. {
  337. $$ = &IfStmt{
  338. If: $1,
  339. Cond: $2,
  340. True: $4,
  341. }
  342. $<lastStmt>$ = $<lastStmt>4
  343. }
  344. | if_chain elif expr ':' suite
  345. {
  346. $$ = $1
  347. inner := $1
  348. for len(inner.False) == 1 {
  349. inner = inner.False[0].(*IfStmt)
  350. }
  351. inner.ElsePos = End{Pos: $2}
  352. inner.False = []Expr{
  353. &IfStmt{
  354. If: $2,
  355. Cond: $3,
  356. True: $5,
  357. },
  358. }
  359. $<lastStmt>$ = $<lastStmt>5
  360. }
  361. // A complete if-elif-elif-else chain
  362. if_else_block:
  363. if_chain
  364. | if_chain _ELSE ':' suite
  365. {
  366. $$ = $1
  367. inner := $1
  368. for len(inner.False) == 1 {
  369. inner = inner.False[0].(*IfStmt)
  370. }
  371. inner.ElsePos = End{Pos: $2}
  372. inner.False = $4
  373. $<lastStmt>$ = $<lastStmt>4
  374. }
  375. elif:
  376. _ELSE _IF
  377. | _ELIF
  378. simple_stmt:
  379. small_stmt small_stmts_continuation semi_opt '\n'
  380. {
  381. $$ = append([]Expr{$1}, $2...)
  382. $<lastStmt>$ = $$[len($$)-1]
  383. }
  384. small_stmts_continuation:
  385. {
  386. $$ = []Expr{}
  387. }
  388. | small_stmts_continuation ';' small_stmt
  389. {
  390. $$ = append($1, $3)
  391. }
  392. small_stmt:
  393. expr %prec ShiftInstead
  394. | _RETURN expr
  395. {
  396. $$ = &ReturnStmt{
  397. Return: $1,
  398. Result: $2,
  399. }
  400. }
  401. | _RETURN
  402. {
  403. $$ = &ReturnStmt{
  404. Return: $1,
  405. }
  406. }
  407. | expr '=' expr { $$ = binary($1, $2, $<tok>2, $3) }
  408. | expr _AUGM expr { $$ = binary($1, $2, $<tok>2, $3) }
  409. | _PASS
  410. {
  411. $$ = &BranchStmt{
  412. Token: $<tok>1,
  413. TokenPos: $1,
  414. }
  415. }
  416. | _BREAK
  417. {
  418. $$ = &BranchStmt{
  419. Token: $<tok>1,
  420. TokenPos: $1,
  421. }
  422. }
  423. | _CONTINUE
  424. {
  425. $$ = &BranchStmt{
  426. Token: $<tok>1,
  427. TokenPos: $1,
  428. }
  429. }
  430. semi_opt:
  431. | ';'
  432. primary_expr:
  433. ident
  434. | number
  435. | primary_expr '.' _IDENT
  436. {
  437. $$ = &DotExpr{
  438. X: $1,
  439. Dot: $2,
  440. NamePos: $3,
  441. Name: $<tok>3,
  442. }
  443. }
  444. | _LOAD '(' string ',' load_arguments comma_opt ')'
  445. {
  446. load := &LoadStmt{
  447. Load: $1,
  448. Module: $3,
  449. Rparen: End{Pos: $7},
  450. ForceCompact: $1.Line == $7.Line,
  451. }
  452. for _, arg := range $5 {
  453. load.From = append(load.From, &arg.from)
  454. load.To = append(load.To, &arg.to)
  455. }
  456. $$ = load
  457. }
  458. | primary_expr '(' arguments_opt ')'
  459. {
  460. $$ = &CallExpr{
  461. X: $1,
  462. ListStart: $2,
  463. List: $3,
  464. End: End{Pos: $4},
  465. ForceCompact: forceCompact($2, $3, $4),
  466. ForceMultiLine: forceMultiLine($2, $3, $4),
  467. }
  468. }
  469. | primary_expr '[' expr ']'
  470. {
  471. $$ = &IndexExpr{
  472. X: $1,
  473. IndexStart: $2,
  474. Y: $3,
  475. End: $4,
  476. }
  477. }
  478. | primary_expr '[' expr_opt ':' test_opt ']'
  479. {
  480. $$ = &SliceExpr{
  481. X: $1,
  482. SliceStart: $2,
  483. From: $3,
  484. FirstColon: $4,
  485. To: $5,
  486. End: $6,
  487. }
  488. }
  489. | primary_expr '[' expr_opt ':' test_opt ':' test_opt ']'
  490. {
  491. $$ = &SliceExpr{
  492. X: $1,
  493. SliceStart: $2,
  494. From: $3,
  495. FirstColon: $4,
  496. To: $5,
  497. SecondColon: $6,
  498. Step: $7,
  499. End: $8,
  500. }
  501. }
  502. | strings %prec ShiftInstead
  503. {
  504. if len($1) == 1 {
  505. $$ = $1[0]
  506. break
  507. }
  508. $$ = $1[0]
  509. for _, x := range $1[1:] {
  510. _, end := $$.Span()
  511. $$ = binary($$, end, "+", x)
  512. }
  513. }
  514. | '[' tests_opt ']'
  515. {
  516. $$ = &ListExpr{
  517. Start: $1,
  518. List: $2,
  519. End: End{Pos: $3},
  520. ForceMultiLine: forceMultiLine($1, $2, $3),
  521. }
  522. }
  523. | '[' test for_clauses_with_if_clauses_opt ']'
  524. {
  525. $$ = &Comprehension{
  526. Curly: false,
  527. Lbrack: $1,
  528. Body: $2,
  529. Clauses: $3,
  530. End: End{Pos: $4},
  531. ForceMultiLine: forceMultiLineComprehension($1, $2, $3, $4),
  532. }
  533. }
  534. | '{' keyvalue for_clauses_with_if_clauses_opt '}'
  535. {
  536. $$ = &Comprehension{
  537. Curly: true,
  538. Lbrack: $1,
  539. Body: $2,
  540. Clauses: $3,
  541. End: End{Pos: $4},
  542. ForceMultiLine: forceMultiLineComprehension($1, $2, $3, $4),
  543. }
  544. }
  545. | '{' keyvalues '}'
  546. {
  547. $$ = &DictExpr{
  548. Start: $1,
  549. List: $2,
  550. End: End{Pos: $3},
  551. ForceMultiLine: forceMultiLine($1, $2, $3),
  552. }
  553. }
  554. | '{' tests comma_opt '}' // TODO: remove, not supported
  555. {
  556. $$ = &SetExpr{
  557. Start: $1,
  558. List: $2,
  559. End: End{Pos: $4},
  560. ForceMultiLine: forceMultiLine($1, $2, $4),
  561. }
  562. }
  563. | '(' tests_opt ')'
  564. {
  565. if len($2) == 1 && $<comma>2.Line == 0 {
  566. // Just a parenthesized expression, not a tuple.
  567. $$ = &ParenExpr{
  568. Start: $1,
  569. X: $2[0],
  570. End: End{Pos: $3},
  571. ForceMultiLine: forceMultiLine($1, $2, $3),
  572. }
  573. } else {
  574. $$ = &TupleExpr{
  575. Start: $1,
  576. List: $2,
  577. End: End{Pos: $3},
  578. ForceCompact: forceCompact($1, $2, $3),
  579. ForceMultiLine: forceMultiLine($1, $2, $3),
  580. }
  581. }
  582. }
  583. arguments_opt:
  584. {
  585. $$ = nil
  586. }
  587. | arguments comma_opt
  588. {
  589. $$ = $1
  590. }
  591. arguments:
  592. argument
  593. {
  594. $$ = []Expr{$1}
  595. }
  596. | arguments ',' argument
  597. {
  598. $$ = append($1, $3)
  599. }
  600. argument:
  601. test
  602. | ident '=' test
  603. {
  604. $$ = binary($1, $2, $<tok>2, $3)
  605. }
  606. | '*' test
  607. {
  608. $$ = unary($1, $<tok>1, $2)
  609. }
  610. | _STAR_STAR test
  611. {
  612. $$ = unary($1, $<tok>1, $2)
  613. }
  614. load_arguments:
  615. load_argument {
  616. $$ = []*struct{from Ident; to Ident}{$1}
  617. }
  618. | load_arguments ',' load_argument
  619. {
  620. $1 = append($1, $3)
  621. $$ = $1
  622. }
  623. load_argument:
  624. string {
  625. start := $1.Start.add("'")
  626. if $1.TripleQuote {
  627. start = start.add("''")
  628. }
  629. $$ = &struct{from Ident; to Ident}{
  630. from: Ident{
  631. Name: $1.Value,
  632. NamePos: start,
  633. },
  634. to: Ident{
  635. Name: $1.Value,
  636. NamePos: start,
  637. },
  638. }
  639. }
  640. | ident '=' string
  641. {
  642. start := $3.Start.add("'")
  643. if $3.TripleQuote {
  644. start = start.add("''")
  645. }
  646. $$ = &struct{from Ident; to Ident}{
  647. from: Ident{
  648. Name: $3.Value,
  649. NamePos: start,
  650. },
  651. to: *$1.(*Ident),
  652. }
  653. }
  654. parameters_opt:
  655. {
  656. $$ = nil
  657. }
  658. | parameters comma_opt
  659. {
  660. $$ = $1
  661. }
  662. parameters:
  663. parameter
  664. {
  665. $$ = []Expr{$1}
  666. }
  667. | parameters ',' parameter
  668. {
  669. $$ = append($1, $3)
  670. }
  671. parameter:
  672. ident
  673. | ident '=' test
  674. {
  675. $$ = binary($1, $2, $<tok>2, $3)
  676. }
  677. | '*' ident
  678. {
  679. $$ = unary($1, $<tok>1, $2)
  680. }
  681. | '*'
  682. {
  683. $$ = unary($1, $<tok>1, nil)
  684. }
  685. | _STAR_STAR ident
  686. {
  687. $$ = unary($1, $<tok>1, $2)
  688. }
  689. expr:
  690. test
  691. | expr ',' test
  692. {
  693. tuple, ok := $1.(*TupleExpr)
  694. if !ok || !tuple.NoBrackets {
  695. tuple = &TupleExpr{
  696. List: []Expr{$1},
  697. NoBrackets: true,
  698. ForceCompact: true,
  699. ForceMultiLine: false,
  700. }
  701. }
  702. tuple.List = append(tuple.List, $3)
  703. $$ = tuple
  704. }
  705. expr_opt:
  706. {
  707. $$ = nil
  708. }
  709. | expr
  710. exprs:
  711. expr
  712. {
  713. $$ = []Expr{$1}
  714. }
  715. | exprs ',' expr
  716. {
  717. $$ = append($1, $3)
  718. }
  719. exprs_opt:
  720. {
  721. $$ = nil
  722. }
  723. | exprs comma_opt
  724. {
  725. $$ = $1
  726. }
  727. test:
  728. primary_expr
  729. | _LAMBDA exprs_opt ':' expr // TODO: remove, not supported
  730. {
  731. $$ = &LambdaExpr{
  732. Function: Function{
  733. StartPos: $1,
  734. Params: $2,
  735. Body: []Expr{$4},
  736. },
  737. }
  738. }
  739. | _NOT test %prec _UNARY { $$ = unary($1, $<tok>1, $2) }
  740. | '-' test %prec _UNARY { $$ = unary($1, $<tok>1, $2) }
  741. | '+' test %prec _UNARY { $$ = unary($1, $<tok>1, $2) }
  742. | '~' test %prec _UNARY { $$ = unary($1, $<tok>1, $2) }
  743. | test '*' test { $$ = binary($1, $2, $<tok>2, $3) }
  744. | test '%' test { $$ = binary($1, $2, $<tok>2, $3) }
  745. | test '/' test { $$ = binary($1, $2, $<tok>2, $3) }
  746. | test _INT_DIV test { $$ = binary($1, $2, $<tok>2, $3) }
  747. | test '+' test { $$ = binary($1, $2, $<tok>2, $3) }
  748. | test '-' test { $$ = binary($1, $2, $<tok>2, $3) }
  749. | test '<' test { $$ = binary($1, $2, $<tok>2, $3) }
  750. | test '>' test { $$ = binary($1, $2, $<tok>2, $3) }
  751. | test _EQ test { $$ = binary($1, $2, $<tok>2, $3) }
  752. | test _LE test { $$ = binary($1, $2, $<tok>2, $3) }
  753. | test _NE test { $$ = binary($1, $2, $<tok>2, $3) }
  754. | test _GE test { $$ = binary($1, $2, $<tok>2, $3) }
  755. | test _IN test { $$ = binary($1, $2, $<tok>2, $3) }
  756. | test _NOT _IN test { $$ = binary($1, $2, "not in", $4) }
  757. | test _OR test { $$ = binary($1, $2, $<tok>2, $3) }
  758. | test _AND test { $$ = binary($1, $2, $<tok>2, $3) }
  759. | test '|' test { $$ = binary($1, $2, $<tok>2, $3) }
  760. | test '&' test { $$ = binary($1, $2, $<tok>2, $3) }
  761. | test '^' test { $$ = binary($1, $2, $<tok>2, $3) }
  762. | test _BIT_LSH test { $$ = binary($1, $2, $<tok>2, $3) }
  763. | test _BIT_RSH test { $$ = binary($1, $2, $<tok>2, $3) }
  764. | test _IS test
  765. {
  766. if b, ok := $3.(*UnaryExpr); ok && b.Op == "not" {
  767. $$ = binary($1, $2, "is not", b.X)
  768. } else {
  769. $$ = binary($1, $2, $<tok>2, $3)
  770. }
  771. }
  772. | test _IF test _ELSE test
  773. {
  774. $$ = &ConditionalExpr{
  775. Then: $1,
  776. IfStart: $2,
  777. Test: $3,
  778. ElseStart: $4,
  779. Else: $5,
  780. }
  781. }
  782. tests:
  783. test
  784. {
  785. $$ = []Expr{$1}
  786. }
  787. | tests ',' test
  788. {
  789. $$ = append($1, $3)
  790. }
  791. test_opt:
  792. {
  793. $$ = nil
  794. }
  795. | test
  796. tests_opt:
  797. {
  798. $$, $<comma>$ = nil, Position{}
  799. }
  800. | tests comma_opt
  801. {
  802. $$, $<comma>$ = $1, $2
  803. }
  804. // comma_opt is an optional comma. If the comma is present,
  805. // the rule's value is the position of the comma. Otherwise
  806. // the rule's value is the zero position. Tracking this
  807. // lets us distinguish (x) and (x,).
  808. comma_opt:
  809. {
  810. $$ = Position{}
  811. }
  812. | ','
  813. keyvalue:
  814. test ':' test {
  815. $$ = &KeyValueExpr{
  816. Key: $1,
  817. Colon: $2,
  818. Value: $3,
  819. }
  820. }
  821. keyvalues_no_comma:
  822. keyvalue
  823. {
  824. $$ = []Expr{$1}
  825. }
  826. | keyvalues_no_comma ',' keyvalue
  827. {
  828. $$ = append($1, $3)
  829. }
  830. keyvalues:
  831. {
  832. $$ = nil
  833. }
  834. | keyvalues_no_comma
  835. {
  836. $$ = $1
  837. }
  838. | keyvalues_no_comma ','
  839. {
  840. $$ = $1
  841. }
  842. loop_vars:
  843. primary_expr
  844. | loop_vars ',' primary_expr
  845. {
  846. tuple, ok := $1.(*TupleExpr)
  847. if !ok || !tuple.NoBrackets {
  848. tuple = &TupleExpr{
  849. List: []Expr{$1},
  850. NoBrackets: true,
  851. ForceCompact: true,
  852. ForceMultiLine: false,
  853. }
  854. }
  855. tuple.List = append(tuple.List, $3)
  856. $$ = tuple
  857. }
  858. string:
  859. _STRING
  860. {
  861. $$ = &StringExpr{
  862. Start: $1,
  863. Value: $<str>1,
  864. TripleQuote: $<triple>1,
  865. End: $1.add($<tok>1),
  866. Token: $<tok>1,
  867. }
  868. }
  869. strings:
  870. string
  871. {
  872. $$ = []*StringExpr{$1}
  873. }
  874. | strings string
  875. {
  876. $$ = append($1, $2)
  877. }
  878. ident:
  879. _IDENT
  880. {
  881. $$ = &Ident{NamePos: $1, Name: $<tok>1}
  882. }
  883. number:
  884. _NUMBER
  885. {
  886. $$ = &LiteralExpr{Start: $1, Token: $<tok>1}
  887. }
  888. for_clause:
  889. _FOR loop_vars _IN test
  890. {
  891. $$ = &ForClause{
  892. For: $1,
  893. Vars: $2,
  894. In: $3,
  895. X: $4,
  896. }
  897. }
  898. for_clause_with_if_clauses_opt:
  899. for_clause {
  900. $$ = []Expr{$1}
  901. }
  902. | for_clause_with_if_clauses_opt _IF test {
  903. $$ = append($1, &IfClause{
  904. If: $2,
  905. Cond: $3,
  906. })
  907. }
  908. for_clauses_with_if_clauses_opt:
  909. for_clause_with_if_clauses_opt
  910. {
  911. $$ = $1
  912. }
  913. | for_clauses_with_if_clauses_opt for_clause_with_if_clauses_opt {
  914. $$ = append($1, $2...)
  915. }
  916. %%
  917. // Go helper code.
  918. // unary returns a unary expression with the given
  919. // position, operator, and subexpression.
  920. func unary(pos Position, op string, x Expr) Expr {
  921. return &UnaryExpr{
  922. OpStart: pos,
  923. Op: op,
  924. X: x,
  925. }
  926. }
  927. // binary returns a binary expression with the given
  928. // operands, position, and operator.
  929. func binary(x Expr, pos Position, op string, y Expr) Expr {
  930. _, xend := x.Span()
  931. ystart, _ := y.Span()
  932. switch op {
  933. case "=", "+=", "-=", "*=", "/=", "//=", "%=", "|=":
  934. return &AssignExpr{
  935. LHS: x,
  936. OpPos: pos,
  937. Op: op,
  938. LineBreak: xend.Line < ystart.Line,
  939. RHS: y,
  940. }
  941. }
  942. return &BinaryExpr{
  943. X: x,
  944. OpStart: pos,
  945. Op: op,
  946. LineBreak: xend.Line < ystart.Line,
  947. Y: y,
  948. }
  949. }
  950. // isSimpleExpression returns whether an expression is simple and allowed to exist in
  951. // compact forms of sequences.
  952. // The formal criteria are the following: an expression is considered simple if it's
  953. // a literal (variable, string or a number), a literal with a unary operator or an empty sequence.
  954. func isSimpleExpression(expr *Expr) bool {
  955. switch x := (*expr).(type) {
  956. case *LiteralExpr, *StringExpr, *Ident:
  957. return true
  958. case *UnaryExpr:
  959. _, literal := x.X.(*LiteralExpr)
  960. _, ident := x.X.(*Ident)
  961. return literal || ident
  962. case *ListExpr:
  963. return len(x.List) == 0
  964. case *TupleExpr:
  965. return len(x.List) == 0
  966. case *DictExpr:
  967. return len(x.List) == 0
  968. case *SetExpr:
  969. return len(x.List) == 0
  970. default:
  971. return false
  972. }
  973. }
  974. // forceCompact returns the setting for the ForceCompact field for a call or tuple.
  975. //
  976. // NOTE 1: The field is called ForceCompact, not ForceSingleLine,
  977. // because it only affects the formatting associated with the call or tuple syntax,
  978. // not the formatting of the arguments. For example:
  979. //
  980. // call([
  981. // 1,
  982. // 2,
  983. // 3,
  984. // ])
  985. //
  986. // is still a compact call even though it runs on multiple lines.
  987. //
  988. // In contrast the multiline form puts a linebreak after the (.
  989. //
  990. // call(
  991. // [
  992. // 1,
  993. // 2,
  994. // 3,
  995. // ],
  996. // )
  997. //
  998. // NOTE 2: Because of NOTE 1, we cannot use start and end on the
  999. // same line as a signal for compact mode: the formatting of an
  1000. // embedded list might move the end to a different line, which would
  1001. // then look different on rereading and cause buildifier not to be
  1002. // idempotent. Instead, we have to look at properties guaranteed
  1003. // to be preserved by the reformatting, namely that the opening
  1004. // paren and the first expression are on the same line and that
  1005. // each subsequent expression begins on the same line as the last
  1006. // one ended (no line breaks after comma).
  1007. func forceCompact(start Position, list []Expr, end Position) bool {
  1008. if len(list) <= 1 {
  1009. // The call or tuple will probably be compact anyway; don't force it.
  1010. return false
  1011. }
  1012. // If there are any named arguments or non-string, non-literal
  1013. // arguments, cannot force compact mode.
  1014. line := start.Line
  1015. for _, x := range list {
  1016. start, end := x.Span()
  1017. if start.Line != line {
  1018. return false
  1019. }
  1020. line = end.Line
  1021. if !isSimpleExpression(&x) {
  1022. return false
  1023. }
  1024. }
  1025. return end.Line == line
  1026. }
  1027. // forceMultiLine returns the setting for the ForceMultiLine field.
  1028. func forceMultiLine(start Position, list []Expr, end Position) bool {
  1029. if len(list) > 1 {
  1030. // The call will be multiline anyway, because it has multiple elements. Don't force it.
  1031. return false
  1032. }
  1033. if len(list) == 0 {
  1034. // Empty list: use position of brackets.
  1035. return start.Line != end.Line
  1036. }
  1037. // Single-element list.
  1038. // Check whether opening bracket is on different line than beginning of
  1039. // element, or closing bracket is on different line than end of element.
  1040. elemStart, elemEnd := list[0].Span()
  1041. return start.Line != elemStart.Line || end.Line != elemEnd.Line
  1042. }
  1043. // forceMultiLineComprehension returns the setting for the ForceMultiLine field for a comprehension.
  1044. func forceMultiLineComprehension(start Position, expr Expr, clauses []Expr, end Position) bool {
  1045. // Return true if there's at least one line break between start, expr, each clause, and end
  1046. exprStart, exprEnd := expr.Span()
  1047. if start.Line != exprStart.Line {
  1048. return true
  1049. }
  1050. previousEnd := exprEnd
  1051. for _, clause := range clauses {
  1052. clauseStart, clauseEnd := clause.Span()
  1053. if previousEnd.Line != clauseStart.Line {
  1054. return true
  1055. }
  1056. previousEnd = clauseEnd
  1057. }
  1058. return previousEnd.Line != end.Line
  1059. }
  1060. // extractTrailingComments extracts trailing comments of an indented block starting with the first
  1061. // comment line with indentation less than the block indentation.
  1062. // The comments can either belong to CommentBlock statements or to the last non-comment statement
  1063. // as After-comments.
  1064. func extractTrailingComments(stmt Expr) []Expr {
  1065. body := getLastBody(stmt)
  1066. var comments []Expr
  1067. if body != nil && len(*body) > 0 {
  1068. // Get the current indentation level
  1069. start, _ := (*body)[0].Span()
  1070. indentation := start.LineRune
  1071. // Find the last non-comment statement
  1072. lastNonCommentIndex := -1
  1073. for i, stmt := range *body {
  1074. if _, ok := stmt.(*CommentBlock); !ok {
  1075. lastNonCommentIndex = i
  1076. }
  1077. }
  1078. if lastNonCommentIndex == -1 {
  1079. return comments
  1080. }
  1081. // Iterate over the trailing comments, find the first comment line that's not indented enough,
  1082. // dedent it and all the following comments.
  1083. for i := lastNonCommentIndex; i < len(*body); i++ {
  1084. stmt := (*body)[i]
  1085. if comment := extractDedentedComment(stmt, indentation); comment != nil {
  1086. // This comment and all the following CommentBlock statements are to be extracted.
  1087. comments = append(comments, comment)
  1088. comments = append(comments, (*body)[i+1:]...)
  1089. *body = (*body)[:i+1]
  1090. // If the current statement is a CommentBlock statement without any comment lines
  1091. // it should be removed too.
  1092. if i > lastNonCommentIndex && len(stmt.Comment().After) == 0 {
  1093. *body = (*body)[:i]
  1094. }
  1095. }
  1096. }
  1097. }
  1098. return comments
  1099. }
  1100. // extractDedentedComment extract the first comment line from `stmt` which indentation is smaller
  1101. // than `indentation`, and all following comment lines, and returns them in a newly created
  1102. // CommentBlock statement.
  1103. func extractDedentedComment(stmt Expr, indentation int) Expr {
  1104. for i, line := range stmt.Comment().After {
  1105. // line.Start.LineRune == 0 can't exist in parsed files, it indicates that the comment line
  1106. // has been added by an AST modification. Don't take such lines into account.
  1107. if line.Start.LineRune > 0 && line.Start.LineRune < indentation {
  1108. // This and all the following lines should be dedented
  1109. cb := &CommentBlock{
  1110. Start: line.Start,
  1111. Comments: Comments{After: stmt.Comment().After[i:]},
  1112. }
  1113. stmt.Comment().After = stmt.Comment().After[:i]
  1114. return cb
  1115. }
  1116. }
  1117. return nil
  1118. }
  1119. // getLastBody returns the last body of a block statement (the only body for For- and DefStmt
  1120. // objects, the last in a if-elif-else chain
  1121. func getLastBody(stmt Expr) *[]Expr {
  1122. switch block := stmt.(type) {
  1123. case *DefStmt:
  1124. return &block.Body
  1125. case *ForStmt:
  1126. return &block.Body
  1127. case *IfStmt:
  1128. if len(block.False) == 0 {
  1129. return &block.True
  1130. } else if len(block.False) == 1 {
  1131. if next, ok := block.False[0].(*IfStmt); ok {
  1132. // Recursively find the last block of the chain
  1133. return getLastBody(next)
  1134. }
  1135. }
  1136. return &block.False
  1137. }
  1138. return nil
  1139. }