Skip to content

Commit

Permalink
[bugfix] fix nim-lang#11469, new rules for a newline in nimpretty
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq authored and narimiran committed Jun 14, 2019
1 parent 57a83df commit fd5ae38
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 37 deletions.
79 changes: 57 additions & 22 deletions compiler/layouter.nim
Expand Up @@ -25,7 +25,7 @@ type
detectSemicolonKind, useSemicolon, dontTouch

LayoutToken = enum
ltSpaces, ltNewline, ltTab,
ltSpaces, ltNewline, ltTab, ltOptionalNewline,
ltComment, ltLit, ltKeyword, ltExportMarker, ltIdent,
ltOther, ltOpr,
ltBeginSection, ltEndSection
Expand Down Expand Up @@ -88,14 +88,38 @@ proc computeRhs(em: Emitter; pos: int): int =
inc result, em.tokens[p].len
inc p

proc optionalIsGood(em: Emitter; pos: int): bool =
let ourIndent = em.tokens[pos].len
var p = pos+1
var lineLen = 0
while p < em.tokens.len and em.kinds[p] != ltNewline:
inc lineLen, em.tokens[p].len
inc p
if p+1 < em.tokens.len and em.kinds[p+1] == ltSpaces and
em.tokens[p-1] == "," and
em.tokens[p+1].len != ourIndent:
result = false
elif em.kinds[pos+1] == ltOther: # note: pos+1, not p+1
result = false
else:
result = lineLen > 10 and p > pos + 3

proc lenOfNextTokens(em: Emitter; pos: int, n = 3): int =
result = 0
for i in 1 .. n:
if pos+i < em.tokens.len:
if em.kinds[pos+i] == ltNewline: break
inc result, em.tokens[pos+i].len

proc closeEmitter*(em: var Emitter) =
let outFile = em.config.absOutFile

var content = newStringOfCap(16_000)
var maxLhs = 0
var lineLen = 0
var lineBegin = 0
for i in 0..em.tokens.high:
var i = 0
while i <= em.tokens.high:
case em.kinds[i]
of ltBeginSection:
maxLhs = computeMax(em, lineBegin)
Expand All @@ -113,9 +137,22 @@ proc closeEmitter*(em: var Emitter) =
content.add em.tokens[i]
lineLen = 0
lineBegin = i+1
of ltOptionalNewline:
if lineLen + lenOfNextTokens(em, i) >= MaxLineLen and optionalIsGood(em, i):
if i-1 >= 0 and em.kinds[i-1] == ltSpaces:
let spaces = em.tokens[i-1].len
content.setLen(content.len - spaces)
content.add "\L"
content.add em.tokens[i]
lineLen = em.tokens[i].len
lineBegin = i+1
if i+1 < em.kinds.len and em.kinds[i+1] == ltSpaces:
# inhibit extra spaces at the start of a new line
inc i
else:
content.add em.tokens[i]
inc lineLen, em.tokens[i].len
inc i

if fileExists(outFile) and readFile(outFile.string) == content:
discard "do nothing, see #9499"
Expand Down Expand Up @@ -199,31 +236,29 @@ proc softLinebreak(em: var Emitter, lit: string) =
if em.lastTok in splitters:
# bug #10295, check first if even more indentation would help:
let spaces = em.indentLevel+moreIndent(em)
if spaces < em.col:
removeSpaces em
wrNewline(em)
em.col = 0
wrSpaces em, spaces
if spaces < em.col and spaces > 0:
wr(em, strutils.repeat(' ', spaces), ltOptionalNewline)
else:
# search backwards for a good split position:
for a in mitems(em.altSplitPos):
if a > em.fixedUntil:
var spaces = 0
while a+spaces < em.kinds.len and em.kinds[a+spaces] == ltSpaces:
inc spaces
if spaces > 0:
delete(em.tokens, a, a+spaces-1)
delete(em.kinds, a, a+spaces-1)
em.kinds.insert(ltNewline, a)
em.tokens.insert("\L", a)
em.kinds.insert(ltSpaces, a+1)
when false:
var spaces = 0
while a+spaces < em.kinds.len and em.kinds[a+spaces] in {ltSpaces, ltOptionalNewline}:
inc spaces
if spaces > 0:
delete(em.tokens, a, a+spaces-1)
delete(em.kinds, a, a+spaces-1)

em.kinds.insert(ltOptionalNewline, a+1)
em.tokens.insert(repeat(' ', em.indentLevel+moreIndent(em)), a+1)
# recompute em.col:
var i = em.kinds.len-1
em.col = 0
while i >= 0 and em.kinds[i] != ltNewline:
inc em.col, em.tokens[i].len
dec i
when false:
# recompute em.col:
var i = em.kinds.len-1
em.col = 0
while i >= 0 and em.kinds[i] != ltNewline:
inc em.col, em.tokens[i].len
dec i
# mark position as "already split here"
a = -1
break
Expand Down
2 changes: 2 additions & 0 deletions compiler/parser.nim
Expand Up @@ -904,6 +904,7 @@ proc parsePragma(p: var TParser): PNode =
result = newNodeP(nkPragma, p)
inc p.inPragma
when defined(nimpretty):
inc p.em.doIndentMore
inc p.em.keepIndents
getTok(p)
optInd(p, result)
Expand All @@ -924,6 +925,7 @@ proc parsePragma(p: var TParser): PNode =
parMessage(p, "expected '.}'")
dec p.inPragma
when defined(nimpretty):
dec p.em.doIndentMore
dec p.em.keepIndents

proc identVis(p: var TParser; allowDot=false): PNode =
Expand Down
19 changes: 7 additions & 12 deletions nimpretty/tests/expected/exhaustive.nim
Expand Up @@ -15,8 +15,7 @@ let expr = if true: "true" else: "false"

var body = newNimNode(nnkIfExpr).add(
newNimNode(nnkElifBranch).add(
infix(newDotExpr(ident("a"), ident("kind")), "==", newDotExpr(ident("b"),
ident("kind"))),
infix(newDotExpr(ident("a"), ident("kind")), "==", newDotExpr(ident("b"), ident("kind"))),
condition
),
newNimNode(nnkElse).add(newStmtList(newNimNode(nnkReturnStmt).add(ident(
Expand Down Expand Up @@ -125,8 +124,8 @@ type
fixedUntil: int # marks where we must not go in the content
altSplitPos: array[SplitKind, int] # alternative split positions

proc openEmitter*[T, S](em: var Emitter; config: ConfigRef;
fileIdx: FileIndex) {.pragmaHereWrongCurlyEnd.} =
proc openEmitter*[T, S](em: var Emitter; config: ConfigRef; fileIdx: FileIndex) {.
pragmaHereWrongCurlyEnd.} =
let outfile = changeFileExt(config.toFullPath(fileIdx), ".pretty.nim")
em.f = llStreamOpen(outfile, fmWrite)
em.config = config
Expand Down Expand Up @@ -200,8 +199,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
if em.lineSpan > 0: calcCol(em, lit)
if not endsInWhite(em):
wr(" ")
if em.lineSpan == 0 and max(em.col,
LineCommentColumn) + lit.len <= MaxLineLen:
if em.lineSpan == 0 and max(em.col, LineCommentColumn) + lit.len <= MaxLineLen:
for i in 1 .. LineCommentColumn - em.col: wr(" ")
wr lit

Expand All @@ -219,8 +217,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
"case returns value"


if tok.tokType == tkComment and tok.line == em.lastLineNumber and
tok.indent >= 0:
if tok.tokType == tkComment and tok.line == em.lastLineNumber and tok.indent >= 0:
# we have an inline comment so handle it before the indentation token:
emitComment(em, tok)
preventComment = true
Expand Down Expand Up @@ -289,8 +286,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
tkGTripleStrLit, tkCharLit:
let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB)
softLinebreak(em, lit)
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wr(
" ")
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wr(" ")
em.lineSpan = countNewlines(lit)
if em.lineSpan > 0: calcCol(em, lit)
wr lit
Expand Down Expand Up @@ -383,8 +379,7 @@ import osproc
let res = execProcess(
"echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates")

let res = execProcess(
"echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates")
let res = execProcess("echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates")


# bug #10177
Expand Down
5 changes: 2 additions & 3 deletions nimpretty/tests/expected/simple3.nim
Expand Up @@ -8,9 +8,8 @@ foo bar
proc fun() =
echo "ok1"

proc fun2(a = "fooo" & "bar" & "bar" & "bar" & "bar" & (
"bar" & "bar" & "bar") & "bar" & "bar" & "bar" & "bar" & "bar" & "bar" &
"bar" & "bar" & "bar"): auto =
proc fun2(a = "fooo" & "bar" & "bar" & "bar" & "bar" & ("bar" & "bar" & "bar") &
"bar" & "bar" & "bar" & "bar" & "bar" & "bar" & "bar" & "bar" & "bar"): auto =
discard

fun2()

0 comments on commit fd5ae38

Please sign in to comment.