print.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. /*
  2. Copyright 2016 Google Inc. All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // Printing of syntax trees.
  14. package build
  15. import (
  16. "bytes"
  17. "fmt"
  18. "strings"
  19. )
  20. const (
  21. nestedIndentation = 4 // Indentation of nested blocks
  22. listIndentation = 4 // Indentation of multiline expressions
  23. defIndentation = 8 // Indentation of multiline function definitions
  24. )
  25. // Format returns the formatted form of the given BUILD or bzl file.
  26. func Format(f *File) []byte {
  27. pr := &printer{fileType: f.Type}
  28. pr.file(f)
  29. return pr.Bytes()
  30. }
  31. // FormatString returns the string form of the given expression.
  32. func FormatString(x Expr) string {
  33. fileType := TypeBuild // for compatibility
  34. if file, ok := x.(*File); ok {
  35. fileType = file.Type
  36. }
  37. pr := &printer{fileType: fileType}
  38. switch x := x.(type) {
  39. case *File:
  40. pr.file(x)
  41. default:
  42. pr.expr(x, precLow)
  43. }
  44. return pr.String()
  45. }
  46. // A printer collects the state during printing of a file or expression.
  47. type printer struct {
  48. fileType FileType // different rules can be applied to different file types.
  49. bytes.Buffer // output buffer
  50. comment []Comment // pending end-of-line comments
  51. margin int // left margin (indent), a number of spaces
  52. depth int // nesting depth inside ( ) [ ] { }
  53. level int // nesting level of def-, if-else- and for-blocks
  54. needsNewLine bool // true if the next statement needs a new line before it
  55. }
  56. // printf prints to the buffer.
  57. func (p *printer) printf(format string, args ...interface{}) {
  58. fmt.Fprintf(p, format, args...)
  59. }
  60. // indent returns the position on the current line, in bytes, 0-indexed.
  61. func (p *printer) indent() int {
  62. b := p.Bytes()
  63. n := 0
  64. for n < len(b) && b[len(b)-1-n] != '\n' {
  65. n++
  66. }
  67. return n
  68. }
  69. // newline ends the current line, flushing end-of-line comments.
  70. // It must only be called when printing a newline is known to be safe:
  71. // when not inside an expression or when p.depth > 0.
  72. // To break a line inside an expression that might not be enclosed
  73. // in brackets of some kind, use breakline instead.
  74. func (p *printer) newline() {
  75. p.needsNewLine = false
  76. if len(p.comment) > 0 {
  77. p.printf(" ")
  78. for i, com := range p.comment {
  79. if i > 0 {
  80. p.trim()
  81. p.printf("\n%*s", p.margin, "")
  82. }
  83. p.printf("%s", strings.TrimSpace(com.Token))
  84. }
  85. p.comment = p.comment[:0]
  86. }
  87. p.trim()
  88. p.printf("\n%*s", p.margin, "")
  89. }
  90. // softNewline postpones a call to newline to the next call of p.newlineIfNeeded()
  91. // If softNewline is called several times, just one newline is printed.
  92. // Usecase: if there are several nested blocks ending at the same time, for instance
  93. //
  94. // if True:
  95. // for a in b:
  96. // pass
  97. // foo()
  98. //
  99. // the last statement (`pass`) doesn't end with a newline, each block ends with a lazy newline
  100. // which actually gets printed only once when right before the next statement (`foo()`) is printed.
  101. func (p *printer) softNewline() {
  102. p.needsNewLine = true
  103. }
  104. // newlineIfNeeded calls newline if softNewline() has previously been called
  105. func (p *printer) newlineIfNeeded() {
  106. if p.needsNewLine == true {
  107. p.newline()
  108. }
  109. }
  110. // breakline breaks the current line, inserting a continuation \ if needed.
  111. // If no continuation \ is needed, breakline flushes end-of-line comments.
  112. func (p *printer) breakline() {
  113. if p.depth == 0 {
  114. // Cannot have both final \ and comments.
  115. p.printf(" \\\n%*s", p.margin, "")
  116. return
  117. }
  118. // Safe to use newline.
  119. p.newline()
  120. }
  121. // trim removes trailing spaces from the current line.
  122. func (p *printer) trim() {
  123. // Remove trailing space from line we're about to end.
  124. b := p.Bytes()
  125. n := len(b)
  126. for n > 0 && b[n-1] == ' ' {
  127. n--
  128. }
  129. p.Truncate(n)
  130. }
  131. // file formats the given file into the print buffer.
  132. func (p *printer) file(f *File) {
  133. for _, com := range f.Before {
  134. p.printf("%s", strings.TrimSpace(com.Token))
  135. p.newline()
  136. }
  137. p.statements(f.Stmt)
  138. for _, com := range f.After {
  139. p.printf("%s", strings.TrimSpace(com.Token))
  140. p.newline()
  141. }
  142. p.newlineIfNeeded()
  143. }
  144. func (p *printer) nestedStatements(stmts []Expr) {
  145. p.margin += nestedIndentation
  146. p.level++
  147. p.newline()
  148. p.statements(stmts)
  149. p.margin -= nestedIndentation
  150. p.level--
  151. }
  152. func (p *printer) statements(rawStmts []Expr) {
  153. // rawStmts may contain nils if a refactoring tool replaces an actual statement with nil.
  154. // It means the statements don't exist anymore, just ignore them.
  155. stmts := []Expr{}
  156. for _, stmt := range rawStmts {
  157. if stmt != nil {
  158. stmts = append(stmts, stmt)
  159. }
  160. }
  161. for i, stmt := range stmts {
  162. switch stmt := stmt.(type) {
  163. case *CommentBlock:
  164. // comments already handled
  165. default:
  166. p.expr(stmt, precLow)
  167. }
  168. // A CommentBlock is an empty statement without a body,
  169. // it doesn't need an line break after the body
  170. if _, ok := stmt.(*CommentBlock); !ok {
  171. p.softNewline()
  172. }
  173. for _, com := range stmt.Comment().After {
  174. p.newlineIfNeeded()
  175. p.printf("%s", strings.TrimSpace(com.Token))
  176. p.softNewline()
  177. }
  178. // Print an empty line break after the statement unless it's the last statement in the sequence.
  179. // In that case a line break should be printed when the block or the file ends.
  180. if i < len(stmts)-1 {
  181. p.newline()
  182. }
  183. if i+1 < len(stmts) && !p.compactStmt(stmt, stmts[i+1]) {
  184. p.newline()
  185. }
  186. }
  187. }
  188. // compactStmt reports whether the pair of statements s1, s2
  189. // should be printed without an intervening blank line.
  190. // We omit the blank line when both are subinclude statements
  191. // and the second one has no leading comments.
  192. func (p *printer) compactStmt(s1, s2 Expr) bool {
  193. if len(s2.Comment().Before) > 0 {
  194. return false
  195. } else if isLoad(s1) && isLoad(s2) {
  196. // Load statements should be compact
  197. return true
  198. } else if isLoad(s1) || isLoad(s2) {
  199. // Load statements should be separated from anything else
  200. return false
  201. } else if isCommentBlock(s1) || isCommentBlock(s2) {
  202. // Standalone comment blocks shouldn't be attached to other statements
  203. return false
  204. } else if (p.fileType == TypeBuild || p.fileType == TypeWorkspace) && p.level == 0 {
  205. // Top-level statements in a BUILD or WORKSPACE file
  206. return false
  207. } else if isFunctionDefinition(s1) || isFunctionDefinition(s2) {
  208. // On of the statements is a function definition
  209. return false
  210. } else {
  211. // Depend on how the statements have been printed in the original file
  212. _, end := s1.Span()
  213. start, _ := s2.Span()
  214. return start.Line-end.Line <= 1
  215. }
  216. }
  217. // isLoad reports whether x is a load statement.
  218. func isLoad(x Expr) bool {
  219. _, ok := x.(*LoadStmt)
  220. return ok
  221. }
  222. // isCommentBlock reports whether x is a comment block node.
  223. func isCommentBlock(x Expr) bool {
  224. _, ok := x.(*CommentBlock)
  225. return ok
  226. }
  227. // isFunctionDefinition checks if the statement is a def code block
  228. func isFunctionDefinition(x Expr) bool {
  229. _, ok := x.(*DefStmt)
  230. return ok
  231. }
  232. // isDifferentLines reports whether two positions belong to different lines.
  233. // If one of the positions is null (Line == 0), it's not a real position but probably an indicator
  234. // of manually inserted node. Return false in this case
  235. func isDifferentLines(p1, p2 *Position) bool {
  236. if p1.Line == 0 || p2.Line == 0 {
  237. return false
  238. }
  239. return p1.Line != p2.Line
  240. }
  241. // Expression formatting.
  242. // The expression formatter must introduce parentheses to force the
  243. // meaning described by the parse tree. We preserve parentheses in the
  244. // input, so extra parentheses are only needed if we have edited the tree.
  245. //
  246. // For example consider these expressions:
  247. // (1) "x" "y" % foo
  248. // (2) "x" + "y" % foo
  249. // (3) "x" + ("y" % foo)
  250. // (4) ("x" + "y") % foo
  251. // When we parse (1), we represent the concatenation as an addition.
  252. // However, if we print the addition back out without additional parens,
  253. // as in (2), it has the same meaning as (3), which is not the original
  254. // meaning. To preserve the original meaning we must add parens as in (4).
  255. //
  256. // To allow arbitrary rewrites to be formatted properly, we track full
  257. // operator precedence while printing instead of just handling this one
  258. // case of string concatenation.
  259. //
  260. // The precedences are assigned values low to high. A larger number
  261. // binds tighter than a smaller number. All binary operators bind
  262. // left-to-right.
  263. const (
  264. precLow = iota
  265. precAssign
  266. precColon
  267. precIfElse
  268. precOr
  269. precAnd
  270. precCmp
  271. precBitwiseOr
  272. precBitwiseXor
  273. precBitwiseAnd
  274. precBitwiseShift
  275. precAdd
  276. precMultiply
  277. precUnary
  278. precSuffix
  279. )
  280. // opPrec gives the precedence for operators found in a BinaryExpr.
  281. var opPrec = map[string]int{
  282. "or": precOr,
  283. "and": precAnd,
  284. "in": precCmp,
  285. "not in": precCmp,
  286. "<": precCmp,
  287. ">": precCmp,
  288. "==": precCmp,
  289. "!=": precCmp,
  290. "<=": precCmp,
  291. ">=": precCmp,
  292. "+": precAdd,
  293. "-": precAdd,
  294. "*": precMultiply,
  295. "/": precMultiply,
  296. "//": precMultiply,
  297. "%": precMultiply,
  298. "|": precBitwiseOr,
  299. "&": precBitwiseAnd,
  300. "^": precBitwiseXor,
  301. "<<": precBitwiseShift,
  302. ">>": precBitwiseShift,
  303. }
  304. // expr prints the expression v to the print buffer.
  305. // The value outerPrec gives the precedence of the operator
  306. // outside expr. If that operator binds tighter than v's operator,
  307. // expr must introduce parentheses to preserve the meaning
  308. // of the parse tree (see above).
  309. func (p *printer) expr(v Expr, outerPrec int) {
  310. // Emit line-comments preceding this expression.
  311. // If we are in the middle of an expression but not inside ( ) [ ] { }
  312. // then we cannot just break the line: we'd have to end it with a \.
  313. // However, even then we can't emit line comments since that would
  314. // end the expression. This is only a concern if we have rewritten
  315. // the parse tree. If comments were okay before this expression in
  316. // the original input they're still okay now, in the absense of rewrites.
  317. //
  318. // TODO(bazel-team): Check whether it is valid to emit comments right now,
  319. // and if not, insert them earlier in the output instead, at the most
  320. // recent \n not following a \ line.
  321. p.newlineIfNeeded()
  322. if before := v.Comment().Before; len(before) > 0 {
  323. // Want to print a line comment.
  324. // Line comments must be at the current margin.
  325. p.trim()
  326. if p.indent() > 0 {
  327. // There's other text on the line. Start a new line.
  328. p.printf("\n")
  329. }
  330. // Re-indent to margin.
  331. p.printf("%*s", p.margin, "")
  332. for _, com := range before {
  333. p.printf("%s", strings.TrimSpace(com.Token))
  334. p.newline()
  335. }
  336. }
  337. // Do we introduce parentheses?
  338. // The result depends on the kind of expression.
  339. // Each expression type that might need parentheses
  340. // calls addParen with its own precedence.
  341. // If parentheses are necessary, addParen prints the
  342. // opening parenthesis and sets parenthesized so that
  343. // the code after the switch can print the closing one.
  344. parenthesized := false
  345. addParen := func(prec int) {
  346. if prec < outerPrec {
  347. p.printf("(")
  348. p.depth++
  349. parenthesized = true
  350. }
  351. }
  352. switch v := v.(type) {
  353. default:
  354. panic(fmt.Errorf("printer: unexpected type %T", v))
  355. case *LiteralExpr:
  356. p.printf("%s", v.Token)
  357. case *Ident:
  358. p.printf("%s", v.Name)
  359. case *BranchStmt:
  360. p.printf("%s", v.Token)
  361. case *StringExpr:
  362. // If the Token is a correct quoting of Value and has double quotes, use it,
  363. // also use it if it has single quotes and the value itself contains a double quote symbol.
  364. // This preserves the specific escaping choices that BUILD authors have made.
  365. s, triple, err := Unquote(v.Token)
  366. if s == v.Value && triple == v.TripleQuote && err == nil {
  367. if strings.HasPrefix(v.Token, `"`) || strings.ContainsRune(v.Value, '"') {
  368. p.printf("%s", v.Token)
  369. break
  370. }
  371. }
  372. p.printf("%s", quote(v.Value, v.TripleQuote))
  373. case *DotExpr:
  374. addParen(precSuffix)
  375. p.expr(v.X, precSuffix)
  376. _, xEnd := v.X.Span()
  377. isMultiline := isDifferentLines(&v.NamePos, &xEnd)
  378. if isMultiline {
  379. p.margin += listIndentation
  380. p.breakline()
  381. }
  382. p.printf(".%s", v.Name)
  383. if isMultiline {
  384. p.margin -= listIndentation
  385. }
  386. case *IndexExpr:
  387. addParen(precSuffix)
  388. p.expr(v.X, precSuffix)
  389. p.printf("[")
  390. p.expr(v.Y, precLow)
  391. p.printf("]")
  392. case *KeyValueExpr:
  393. p.expr(v.Key, precLow)
  394. p.printf(": ")
  395. p.expr(v.Value, precLow)
  396. case *SliceExpr:
  397. addParen(precSuffix)
  398. p.expr(v.X, precSuffix)
  399. p.printf("[")
  400. if v.From != nil {
  401. p.expr(v.From, precLow)
  402. }
  403. p.printf(":")
  404. if v.To != nil {
  405. p.expr(v.To, precLow)
  406. }
  407. if v.SecondColon.Byte != 0 {
  408. p.printf(":")
  409. if v.Step != nil {
  410. p.expr(v.Step, precLow)
  411. }
  412. }
  413. p.printf("]")
  414. case *UnaryExpr:
  415. addParen(precUnary)
  416. if v.Op == "not" {
  417. p.printf("not ") // Requires a space after it.
  418. } else {
  419. p.printf("%s", v.Op)
  420. }
  421. // Use the next precedence level (precSuffix), so that nested unary expressions are parenthesized,
  422. // for example: `not (-(+(~foo)))` instead of `not -+~foo`
  423. if v.X != nil {
  424. p.expr(v.X, precSuffix)
  425. }
  426. case *LambdaExpr:
  427. addParen(precColon)
  428. p.printf("lambda ")
  429. for i, param := range v.Params {
  430. if i > 0 {
  431. p.printf(", ")
  432. }
  433. p.expr(param, precLow)
  434. }
  435. p.printf(": ")
  436. p.expr(v.Body[0], precLow) // lambdas should have exactly one statement
  437. case *BinaryExpr:
  438. // Precedence: use the precedence of the operator.
  439. // Since all binary expressions format left-to-right,
  440. // it is okay for the left side to reuse the same operator
  441. // without parentheses, so we use prec for v.X.
  442. // For the same reason, the right side cannot reuse the same
  443. // operator, or else a parse tree for a + (b + c), where the ( ) are
  444. // not present in the source, will format as a + b + c, which
  445. // means (a + b) + c. Treat the right expression as appearing
  446. // in a context one precedence level higher: use prec+1 for v.Y.
  447. //
  448. // Line breaks: if we are to break the line immediately after
  449. // the operator, introduce a margin at the current column,
  450. // so that the second operand lines up with the first one and
  451. // also so that neither operand can use space to the left.
  452. // If the operator is an =, indent the right side another 4 spaces.
  453. prec := opPrec[v.Op]
  454. addParen(prec)
  455. m := p.margin
  456. if v.LineBreak {
  457. p.margin = p.indent()
  458. }
  459. p.expr(v.X, prec)
  460. p.printf(" %s", v.Op)
  461. if v.LineBreak {
  462. p.breakline()
  463. } else {
  464. p.printf(" ")
  465. }
  466. p.expr(v.Y, prec+1)
  467. p.margin = m
  468. case *AssignExpr:
  469. addParen(precAssign)
  470. m := p.margin
  471. if v.LineBreak {
  472. p.margin = p.indent() + listIndentation
  473. }
  474. p.expr(v.LHS, precAssign)
  475. p.printf(" %s", v.Op)
  476. if v.LineBreak {
  477. p.breakline()
  478. } else {
  479. p.printf(" ")
  480. }
  481. p.expr(v.RHS, precAssign+1)
  482. p.margin = m
  483. case *ParenExpr:
  484. p.seq("()", &v.Start, &[]Expr{v.X}, &v.End, modeParen, false, v.ForceMultiLine)
  485. case *CallExpr:
  486. addParen(precSuffix)
  487. p.expr(v.X, precSuffix)
  488. p.seq("()", &v.ListStart, &v.List, &v.End, modeCall, v.ForceCompact, v.ForceMultiLine)
  489. case *LoadStmt:
  490. addParen(precSuffix)
  491. p.printf("load")
  492. args := []Expr{v.Module}
  493. for i := range v.From {
  494. from := v.From[i]
  495. to := v.To[i]
  496. var arg Expr
  497. if from.Name == to.Name {
  498. // Suffix comments are attached to the `to` token,
  499. // Before comments are attached to the `from` token,
  500. // they need to be combined.
  501. arg = from.asString()
  502. arg.Comment().Before = to.Comment().Before
  503. } else {
  504. arg = &AssignExpr{
  505. LHS: to,
  506. Op: "=",
  507. RHS: from.asString(),
  508. }
  509. }
  510. args = append(args, arg)
  511. }
  512. p.seq("()", &v.Load, &args, &v.Rparen, modeLoad, v.ForceCompact, false)
  513. case *ListExpr:
  514. p.seq("[]", &v.Start, &v.List, &v.End, modeList, false, v.ForceMultiLine)
  515. case *SetExpr:
  516. p.seq("{}", &v.Start, &v.List, &v.End, modeList, false, v.ForceMultiLine)
  517. case *TupleExpr:
  518. mode := modeTuple
  519. if v.NoBrackets {
  520. mode = modeSeq
  521. }
  522. p.seq("()", &v.Start, &v.List, &v.End, mode, v.ForceCompact, v.ForceMultiLine)
  523. case *DictExpr:
  524. var list []Expr
  525. for _, x := range v.List {
  526. list = append(list, x)
  527. }
  528. p.seq("{}", &v.Start, &list, &v.End, modeDict, false, v.ForceMultiLine)
  529. case *Comprehension:
  530. p.listFor(v)
  531. case *ConditionalExpr:
  532. addParen(precSuffix)
  533. p.expr(v.Then, precIfElse)
  534. p.printf(" if ")
  535. p.expr(v.Test, precIfElse)
  536. p.printf(" else ")
  537. p.expr(v.Else, precIfElse)
  538. case *ReturnStmt:
  539. p.printf("return")
  540. if v.Result != nil {
  541. p.printf(" ")
  542. p.expr(v.Result, precLow)
  543. }
  544. case *DefStmt:
  545. p.printf("def ")
  546. p.printf(v.Name)
  547. p.seq("()", &v.StartPos, &v.Params, nil, modeDef, v.ForceCompact, v.ForceMultiLine)
  548. p.printf(":")
  549. p.nestedStatements(v.Body)
  550. case *ForStmt:
  551. p.printf("for ")
  552. p.expr(v.Vars, precLow)
  553. p.printf(" in ")
  554. p.expr(v.X, precLow)
  555. p.printf(":")
  556. p.nestedStatements(v.Body)
  557. case *IfStmt:
  558. block := v
  559. isFirst := true
  560. needsEmptyLine := false
  561. for {
  562. p.newlineIfNeeded()
  563. if !isFirst {
  564. if needsEmptyLine {
  565. p.newline()
  566. }
  567. p.printf("el")
  568. }
  569. p.printf("if ")
  570. p.expr(block.Cond, precLow)
  571. p.printf(":")
  572. p.nestedStatements(block.True)
  573. isFirst = false
  574. _, end := block.True[len(block.True)-1].Span()
  575. needsEmptyLine = block.ElsePos.Pos.Line-end.Line > 1
  576. // If the else-block contains just one statement which is an IfStmt, flatten it as a part
  577. // of if-elif chain.
  578. // Don't do it if the "else" statement has a suffix comment or if the next "if" statement
  579. // has a before-comment.
  580. if len(block.False) != 1 {
  581. break
  582. }
  583. next, ok := block.False[0].(*IfStmt)
  584. if !ok {
  585. break
  586. }
  587. if len(block.ElsePos.Comment().Suffix) == 0 && len(next.Comment().Before) == 0 {
  588. block = next
  589. continue
  590. }
  591. break
  592. }
  593. if len(block.False) > 0 {
  594. p.newlineIfNeeded()
  595. if needsEmptyLine {
  596. p.newline()
  597. }
  598. p.printf("else:")
  599. p.comment = append(p.comment, block.ElsePos.Comment().Suffix...)
  600. p.nestedStatements(block.False)
  601. }
  602. case *ForClause:
  603. p.printf("for ")
  604. p.expr(v.Vars, precLow)
  605. p.printf(" in ")
  606. p.expr(v.X, precLow)
  607. case *IfClause:
  608. p.printf("if ")
  609. p.expr(v.Cond, precLow)
  610. }
  611. // Add closing parenthesis if needed.
  612. if parenthesized {
  613. p.depth--
  614. p.printf(")")
  615. }
  616. // Queue end-of-line comments for printing when we
  617. // reach the end of the line.
  618. p.comment = append(p.comment, v.Comment().Suffix...)
  619. }
  620. // A seqMode describes a formatting mode for a sequence of values,
  621. // like a list or call arguments.
  622. type seqMode int
  623. const (
  624. _ seqMode = iota
  625. modeCall // f(x)
  626. modeList // [x]
  627. modeTuple // (x,)
  628. modeParen // (x)
  629. modeDict // {x:y}
  630. modeSeq // x, y
  631. modeDef // def f(x, y)
  632. modeLoad // load(a, b, c)
  633. )
  634. // useCompactMode reports whether a sequence should be formatted in a compact mode
  635. func (p *printer) useCompactMode(start *Position, list *[]Expr, end *End, mode seqMode, forceCompact, forceMultiLine bool) bool {
  636. // If there are line comments, use multiline
  637. // so we can print the comments before the closing bracket.
  638. for _, x := range *list {
  639. if len(x.Comment().Before) > 0 || (len(x.Comment().Suffix) > 0 && mode != modeDef) {
  640. return false
  641. }
  642. }
  643. if end != nil && len(end.Before) > 0 {
  644. return false
  645. }
  646. // Implicit tuples are always compact
  647. if mode == modeSeq {
  648. return true
  649. }
  650. // In the Default and .bzl printing modes try to keep the original printing style.
  651. // Non-top-level statements and lists of arguments of a function definition
  652. // should also keep the original style regardless of the mode.
  653. if (p.level != 0 || p.fileType == TypeDefault || p.fileType == TypeBzl || mode == modeDef) && mode != modeLoad {
  654. // If every element (including the brackets) ends on the same line where the next element starts,
  655. // use the compact mode, otherwise use multiline mode.
  656. // If an node's line number is 0, it means it doesn't appear in the original file,
  657. // its position shouldn't be taken into account. Unless a sequence is new,
  658. // then use multiline mode if ForceMultiLine mode was set.
  659. previousEnd := start
  660. isNewSeq := start.Line == 0
  661. for _, x := range *list {
  662. start, end := x.Span()
  663. isNewSeq = isNewSeq && start.Line == 0
  664. if isDifferentLines(&start, previousEnd) {
  665. return false
  666. }
  667. if end.Line != 0 {
  668. previousEnd = &end
  669. }
  670. }
  671. if end != nil {
  672. isNewSeq = isNewSeq && end.Pos.Line == 0
  673. if isDifferentLines(previousEnd, &end.Pos) {
  674. return false
  675. }
  676. }
  677. if !isNewSeq {
  678. return true
  679. }
  680. // Use the forceMultiline value for new sequences.
  681. return !forceMultiLine
  682. }
  683. // In Build mode, use the forceMultiline and forceCompact values
  684. if forceMultiLine {
  685. return false
  686. }
  687. if forceCompact {
  688. return true
  689. }
  690. // If neither of the flags are set, use compact mode only for empty or 1-element sequences
  691. return len(*list) <= 1
  692. }
  693. // seq formats a list of values inside a given bracket pair (brack = "()", "[]", "{}").
  694. // The end node holds any trailing comments to be printed just before the
  695. // closing bracket.
  696. // The mode parameter specifies the sequence mode (see above).
  697. // If multiLine is true, seq avoids the compact form even
  698. // for 0- and 1-element sequences.
  699. func (p *printer) seq(brack string, start *Position, list *[]Expr, end *End, mode seqMode, forceCompact, forceMultiLine bool) {
  700. if mode != modeSeq {
  701. p.printf("%s", brack[:1])
  702. }
  703. p.depth++
  704. defer func() {
  705. p.depth--
  706. if mode != modeSeq {
  707. p.printf("%s", brack[1:])
  708. }
  709. }()
  710. if p.useCompactMode(start, list, end, mode, forceCompact, forceMultiLine) {
  711. for i, x := range *list {
  712. if i > 0 {
  713. p.printf(", ")
  714. }
  715. p.expr(x, precLow)
  716. }
  717. // Single-element tuple must end with comma, to mark it as a tuple.
  718. if len(*list) == 1 && mode == modeTuple {
  719. p.printf(",")
  720. }
  721. return
  722. }
  723. // Multi-line form.
  724. indentation := listIndentation
  725. if mode == modeDef {
  726. indentation = defIndentation
  727. }
  728. p.margin += indentation
  729. for i, x := range *list {
  730. // If we are about to break the line before the first
  731. // element and there are trailing end-of-line comments
  732. // waiting to be printed, delay them and print them as
  733. // whole-line comments preceding that element.
  734. // Do this by printing a newline ourselves and positioning
  735. // so that the end-of-line comment, with the two spaces added,
  736. // will line up with the current margin.
  737. if i == 0 && len(p.comment) > 0 {
  738. p.printf("\n%*s", p.margin-2, "")
  739. }
  740. p.newline()
  741. p.expr(x, precLow)
  742. if i+1 < len(*list) || needsTrailingComma(mode, x) {
  743. p.printf(",")
  744. }
  745. }
  746. // Final comments.
  747. if end != nil {
  748. for _, com := range end.Before {
  749. p.newline()
  750. p.printf("%s", strings.TrimSpace(com.Token))
  751. }
  752. }
  753. p.margin -= indentation
  754. // in modeDef print the closing bracket on the same line
  755. if mode != modeDef {
  756. p.newline()
  757. }
  758. }
  759. func needsTrailingComma(mode seqMode, v Expr) bool {
  760. switch mode {
  761. case modeDef:
  762. return false
  763. case modeParen:
  764. return false
  765. case modeCall:
  766. // *args and **kwargs in fn calls
  767. switch v := v.(type) {
  768. case *UnaryExpr:
  769. if v.Op == "*" || v.Op == "**" {
  770. return false
  771. }
  772. }
  773. }
  774. return true
  775. }
  776. // listFor formats a ListForExpr (list comprehension).
  777. // The single-line form is:
  778. // [x for y in z if c]
  779. //
  780. // and the multi-line form is:
  781. // [
  782. // x
  783. // for y in z
  784. // if c
  785. // ]
  786. //
  787. func (p *printer) listFor(v *Comprehension) {
  788. multiLine := v.ForceMultiLine || len(v.End.Before) > 0
  789. // space breaks the line in multiline mode
  790. // or else prints a space.
  791. space := func() {
  792. if multiLine {
  793. p.breakline()
  794. } else {
  795. p.printf(" ")
  796. }
  797. }
  798. open, close := "[", "]"
  799. if v.Curly {
  800. open, close = "{", "}"
  801. }
  802. p.depth++
  803. p.printf("%s", open)
  804. if multiLine {
  805. p.margin += listIndentation
  806. p.newline()
  807. }
  808. p.expr(v.Body, precLow)
  809. for _, c := range v.Clauses {
  810. space()
  811. p.expr(c, precLow)
  812. }
  813. if multiLine {
  814. for _, com := range v.End.Before {
  815. p.newline()
  816. p.printf("%s", strings.TrimSpace(com.Token))
  817. }
  818. p.margin -= listIndentation
  819. p.newline()
  820. }
  821. p.printf("%s", close)
  822. p.depth--
  823. }
  824. func (p *printer) isTopLevel() bool {
  825. return p.margin == 0
  826. }