nimpretty: more features

This commit is contained in:
Andreas Rumpf 2018-06-16 09:53:36 +02:00
commit 7819e63f77
2 changed files with 51 additions and 13 deletions

View file

@ -9,7 +9,6 @@
## Layouter for nimpretty. Still primitive but useful. ## Layouter for nimpretty. Still primitive but useful.
## TODO ## TODO
## - Fix 'echo ()' vs 'echo()' difference!
## - Make indentations consistent. ## - Make indentations consistent.
## - Align 'if' and 'case' expressions properly. ## - Align 'if' and 'case' expressions properly.
@ -31,6 +30,7 @@ type
lastTok: TTokType lastTok: TTokType
inquote: bool inquote: bool
col, lastLineNumber, lineSpan, indentLevel: int col, lastLineNumber, lineSpan, indentLevel: int
doIndentMore*: int
content: string content: string
fixedUntil: int # marks where we must not go in the content fixedUntil: int # marks where we must not go in the content
altSplitPos: array[SplitKind, int] # alternative split positions altSplitPos: array[SplitKind, int] # alternative split positions
@ -77,6 +77,8 @@ template rememberSplit(kind) =
if goodCol(em.col): if goodCol(em.col):
em.altSplitPos[kind] = em.content.len em.altSplitPos[kind] = em.content.len
template moreIndent(em): int = (if em.doIndentMore > 0: 4 else: 2)
proc softLinebreak(em: var Emitter, lit: string) = proc softLinebreak(em: var Emitter, lit: string) =
# XXX Use an algorithm that is outlined here: # XXX Use an algorithm that is outlined here:
# https://llvm.org/devmtg/2013-04/jasper-slides.pdf # https://llvm.org/devmtg/2013-04/jasper-slides.pdf
@ -85,12 +87,12 @@ proc softLinebreak(em: var Emitter, lit: string) =
if em.lastTok in splitters: if em.lastTok in splitters:
wr("\L") wr("\L")
em.col = 0 em.col = 0
for i in 1..em.indentLevel+2: wr(" ") for i in 1..em.indentLevel+moreIndent(em): wr(" ")
else: else:
# search backwards for a good split position: # search backwards for a good split position:
for a in em.altSplitPos: for a in em.altSplitPos:
if a > em.fixedUntil: if a > em.fixedUntil:
let ws = "\L" & repeat(' ',em.indentLevel+2) let ws = "\L" & repeat(' ',em.indentLevel+moreIndent(em))
em.col = em.content.len - a em.col = em.content.len - a
em.content.insert(ws, a) em.content.insert(ws, a)
break break
@ -155,15 +157,19 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
wr(TokTypeToStr[tok.tokType]) wr(TokTypeToStr[tok.tokType])
wr(" ") wr(" ")
rememberSplit(splitComma) rememberSplit(splitComma)
of tkParLe, tkParRi, tkBracketLe, of tkParDotLe, tkParLe, tkBracketDotLe, tkBracketLe,
tkBracketRi, tkCurlyLe, tkCurlyRi, tkCurlyLe, tkCurlyDotLe, tkBracketLeColon:
tkBracketDotLe, tkBracketDotRi, if tok.strongSpaceA > 0 and not em.endsInWhite:
tkCurlyDotLe, tkCurlyDotRi, wr(" ")
tkParDotLe, tkParDotRi, wr(TokTypeToStr[tok.tokType])
tkColonColon, tkDot, tkBracketLeColon: rememberSplit(splitParLe)
of tkParRi,
tkBracketRi, tkCurlyRi,
tkBracketDotRi,
tkCurlyDotRi,
tkParDotRi,
tkColonColon, tkDot:
wr(TokTypeToStr[tok.tokType]) wr(TokTypeToStr[tok.tokType])
if tok.tokType in splitters:
rememberSplit(splitParLe)
of tkEquals: of tkEquals:
if not em.endsInWhite: wr(" ") if not em.endsInWhite: wr(" ")
wr(TokTypeToStr[tok.tokType]) wr(TokTypeToStr[tok.tokType])
@ -206,3 +212,13 @@ proc starWasExportMarker*(em: var Emitter) =
setLen(em.content, em.content.len-3) setLen(em.content, em.content.len-3)
em.content.add("*") em.content.add("*")
dec em.col, 2 dec em.col, 2
proc commaWasSemicolon*(em: var Emitter) =
if em.content.endsWith(", "):
setLen(em.content, em.content.len-2)
em.content.add("; ")
proc curlyRiWasPragma*(em: var Emitter) =
if em.content.endsWith("}"):
setLen(em.content, em.content.len-1)
em.content.add(".}")

View file

@ -408,6 +408,8 @@ proc exprColonEqExpr(p: var TParser): PNode =
proc exprList(p: var TParser, endTok: TTokType, result: PNode) = proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
#| exprList = expr ^+ comma #| exprList = expr ^+ comma
when defined(nimpretty2):
inc p.em.doIndentMore
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
# progress guaranteed # progress guaranteed
@ -417,6 +419,8 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
optInd(p, a) optInd(p, a)
when defined(nimpretty2):
dec p.em.doIndentMore
proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
@ -837,7 +841,11 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
result = parseOperators(p, result, limit, mode) result = parseOperators(p, result, limit, mode)
proc simpleExpr(p: var TParser, mode = pmNormal): PNode = proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
when defined(nimpretty2):
inc p.em.doIndentMore
result = simpleExprAux(p, -1, mode) result = simpleExprAux(p, -1, mode)
when defined(nimpretty2):
dec p.em.doIndentMore
proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
#| condExpr = expr colcom expr optInd #| condExpr = expr colcom expr optInd
@ -912,8 +920,12 @@ proc parsePragma(p: var TParser): PNode =
getTok(p) getTok(p)
skipComment(p, a) skipComment(p, a)
optPar(p) optPar(p)
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p) if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}:
else: parMessage(p, "expected '.}'") when defined(nimpretty2):
curlyRiWasPragma(p.em)
getTok(p)
else:
parMessage(p, "expected '.}'")
dec p.inPragma dec p.inPragma
proc identVis(p: var TParser; allowDot=false): PNode = proc identVis(p: var TParser; allowDot=false): PNode =
@ -1000,6 +1012,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
var a = parseIdentColonEquals(p, {}) var a = parseIdentColonEquals(p, {})
addSon(result, a) addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
commaWasSemicolon(p.em)
getTok(p) getTok(p)
skipComment(p, a) skipComment(p, a)
optPar(p) optPar(p)
@ -1034,6 +1048,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
var a: PNode var a: PNode
result = newNodeP(nkFormalParams, p) result = newNodeP(nkFormalParams, p)
addSon(result, p.emptyNode) # return type addSon(result, p.emptyNode) # return type
when defined(nimpretty2):
inc p.em.doIndentMore
let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0 let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
if hasParLe: if hasParLe:
getTok(p) getTok(p)
@ -1053,6 +1069,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
break break
addSon(result, a) addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
commaWasSemicolon(p.em)
getTok(p) getTok(p)
skipComment(p, a) skipComment(p, a)
optPar(p) optPar(p)
@ -1066,6 +1084,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
elif not retColon and not hasParle: elif not retColon and not hasParle:
# Mark as "not there" in order to mark for deprecation in the semantic pass: # Mark as "not there" in order to mark for deprecation in the semantic pass:
result = p.emptyNode result = p.emptyNode
when defined(nimpretty2):
dec p.em.doIndentMore
proc optPragmas(p: var TParser): PNode = proc optPragmas(p: var TParser): PNode =
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)): if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
@ -1668,6 +1688,8 @@ proc parseGenericParamList(p: var TParser): PNode =
var a = parseGenericParam(p) var a = parseGenericParam(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
commaWasSemicolon(p.em)
getTok(p) getTok(p)
skipComment(p, a) skipComment(p, a)
optPar(p) optPar(p)