nimpretty: nimpretty now understands splitting newlines

This commit is contained in:
Araq 2019-07-04 11:32:15 +02:00
commit a59f0adc50
2 changed files with 34 additions and 8 deletions

View file

@ -143,6 +143,8 @@ proc closeEmitter*(em: var Emitter) =
var lineBegin = 0 var lineBegin = 0
var i = 0 var i = 0
while i <= em.tokens.high: while i <= em.tokens.high:
when defined(debug):
echo "i-th token ", em.kinds[i], " ", em.tokens[i]
case em.kinds[i] case em.kinds[i]
of ltBeginSection: of ltBeginSection:
maxLhs = computeMax(em, lineBegin) maxLhs = computeMax(em, lineBegin)
@ -219,11 +221,24 @@ proc wr(em: var Emitter; x: string; lt: LayoutToken) =
inc em.col, x.len inc em.col, x.len
assert em.tokens.len == em.kinds.len assert em.tokens.len == em.kinds.len
proc wrNewline(em: var Emitter) = proc wrNewline(em: var Emitter; kind = ltCrucialNewline) =
em.tokens.add "\L" em.tokens.add "\L"
em.kinds.add ltCrucialNewline em.kinds.add kind
em.col = 0 em.col = 0
proc newlineWasSplitting*(em: var Emitter) =
if em.kinds.len >= 3 and em.kinds[^3] == ltCrucialNewline:
em.kinds[^3] = ltSplittingNewline
#[
Splitting newlines can occur:
- after commas, semicolon, '[', '('.
- after binary operators, '='.
- after ':' type
We only need parser support for the "after type" case.
]#
proc wrSpaces(em: var Emitter; spaces: int) = proc wrSpaces(em: var Emitter; spaces: int) =
if spaces > 0: if spaces > 0:
wr(em, strutils.repeat(' ', spaces), ltSpaces) wr(em, strutils.repeat(' ', spaces), ltSpaces)
@ -261,7 +276,7 @@ const
tkBracketRi, tkCurlyDotRi, tkBracketRi, tkCurlyDotRi,
tkCurlyRi} tkCurlyRi}
splitters = openPars + {tkComma, tkSemicolon} splitters = openPars + {tkComma, tkSemicolon} # do not add 'tkColon' here!
oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor} tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
@ -366,12 +381,14 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
em.fixedUntil = em.tokens.high em.fixedUntil = em.tokens.high
elif tok.indent >= 0: elif tok.indent >= 0:
var newlineKind = ltCrucialNewline
if em.keepIndents > 0: if em.keepIndents > 0:
em.indentLevel = tok.indent em.indentLevel = tok.indent
elif (em.lastTok in (splitters + oprSet) and tok.tokType notin closedPars): elif (em.lastTok in (splitters + oprSet) and tok.tokType notin closedPars):
# aka: we are in an expression context: # aka: we are in an expression context:
let alignment = max(tok.indent - em.indentStack[^1], 0) let alignment = max(tok.indent - em.indentStack[^1], 0)
em.indentLevel = alignment + em.indentStack.high * em.indWidth em.indentLevel = alignment + em.indentStack.high * em.indWidth
newlineKind = ltSplittingNewline
else: else:
if tok.indent > em.indentStack[^1]: if tok.indent > em.indentStack[^1]:
em.indentStack.add tok.indent em.indentStack.add tok.indent
@ -391,7 +408,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
]# ]#
# remove trailing whitespace: # remove trailing whitespace:
removeSpaces em removeSpaces em
wrNewline em wrNewline em, newlineKind
for i in 2..tok.line - em.lastLineNumber: wrNewline(em) for i in 2..tok.line - em.lastLineNumber: wrNewline(em)
wrSpaces em, em.indentLevel wrSpaces em, em.indentLevel
em.fixedUntil = em.tokens.high em.fixedUntil = em.tokens.high

View file

@ -147,10 +147,17 @@ template withInd(p, body: untyped) =
body body
p.currInd = oldInd p.currInd = oldInd
template newlineWasSplitting(p: var TParser) =
when defined(nimpretty):
layouter.newlineWasSplitting(p.em)
template realInd(p): bool = p.tok.indent > p.currInd template realInd(p): bool = p.tok.indent > p.currInd
template sameInd(p): bool = p.tok.indent == p.currInd template sameInd(p): bool = p.tok.indent == p.currInd
template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0 template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0
proc validInd(p: var TParser): bool {.inline.} =
result = p.tok.indent < 0 or p.tok.indent > p.currInd
proc rawSkipComment(p: var TParser, node: PNode) = proc rawSkipComment(p: var TParser, node: PNode) =
if p.tok.tokType == tkComment: if p.tok.tokType == tkComment:
if node != nil: if node != nil:
@ -367,6 +374,7 @@ proc colonOrEquals(p: var TParser, a: PNode): PNode =
if p.tok.tokType == tkColon: if p.tok.tokType == tkColon:
result = newNodeP(nkExprColonExpr, p) result = newNodeP(nkExprColonExpr, p)
getTok(p) getTok(p)
newlineWasSplitting(p)
#optInd(p, result) #optInd(p, result)
addSon(result, a) addSon(result, a)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
@ -1295,6 +1303,7 @@ proc binaryNot(p: var TParser; a: PNode): PNode =
proc parseTypeDesc(p: var TParser): PNode = proc parseTypeDesc(p: var TParser): PNode =
#| typeDesc = simpleExpr ('not' expr)? #| typeDesc = simpleExpr ('not' expr)?
newlineWasSplitting(p)
result = simpleExpr(p, pmTypeDesc) result = simpleExpr(p, pmTypeDesc)
result = binaryNot(p, result) result = binaryNot(p, result)
@ -1510,6 +1519,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p): elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
# NL terminates: # NL terminates:
addSon(result, p.emptyNode) addSon(result, p.emptyNode)
# nimpretty here!
else: else:
var e = parseExpr(p) var e = parseExpr(p)
e = postExprBlocks(p, e) e = postExprBlocks(p, e)
@ -1722,9 +1732,6 @@ proc parsePattern(p: var TParser): PNode =
result = parseStmt(p) result = parseStmt(p)
eat(p, tkCurlyRi) eat(p, tkCurlyRi)
proc validInd(p: var TParser): bool =
result = p.tok.indent < 0 or p.tok.indent > p.currInd
proc parseRoutine(p: var TParser, kind: TNodeKind): PNode = proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
#| indAndComment = (IND{>} COMMENT)? | COMMENT? #| indAndComment = (IND{>} COMMENT)? | COMMENT?
#| routine = optInd identVis pattern? genericParamList? #| routine = optInd identVis pattern? genericParamList?
@ -1809,7 +1816,7 @@ proc parseEnum(p: var TParser): PNode =
symPragma = newNodeP(nkPragmaExpr, p) symPragma = newNodeP(nkPragmaExpr, p)
addSon(symPragma, a) addSon(symPragma, a)
addSon(symPragma, pragma) addSon(symPragma, pragma)
# nimpretty support here
if p.tok.indent >= 0 and p.tok.indent <= p.currInd: if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
add(result, symPragma) add(result, symPragma)
break break
@ -2219,6 +2226,7 @@ proc parseStmt(p: var TParser): PNode =
#| stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED) #| stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED)
#| / simpleStmt ^+ ';' #| / simpleStmt ^+ ';'
if p.tok.indent > p.currInd: if p.tok.indent > p.currInd:
# nimpretty support here
result = newNodeP(nkStmtList, p) result = newNodeP(nkStmtList, p)
withInd(p): withInd(p):
while true: while true:
@ -2295,6 +2303,7 @@ proc parseTopLevelStmt(p: var TParser): PNode =
result = p.emptyNode result = p.emptyNode
# progress guaranteed # progress guaranteed
while true: while true:
# nimpretty support here
if p.tok.indent != 0: if p.tok.indent != 0:
if p.firstTok and p.tok.indent < 0: discard if p.firstTok and p.tok.indent < 0: discard
elif p.tok.tokType != tkSemiColon: elif p.tok.tokType != tkSemiColon: