diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/layouter.nim | 76 | ||||
-rw-r--r-- | compiler/parser.nim | 26 |
2 files changed, 84 insertions, 18 deletions
diff --git a/compiler/layouter.nim b/compiler/layouter.nim index 90e9d6fd7..ec5d3d088 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -9,7 +9,6 @@ ## Layouter for nimpretty. Still primitive but useful. ## TODO -## - Fix 'echo ()' vs 'echo()' difference! ## - Make indentations consistent. ## - Align 'if' and 'case' expressions properly. @@ -30,7 +29,9 @@ type fid: FileIndex lastTok: TTokType inquote: bool - col, lastLineNumber, lineSpan, indentLevel: int + col, lastLineNumber, lineSpan, indentLevel, indWidth: int + lastIndent: int + doIndentMore*: int content: string fixedUntil: int # marks where we must not go in the content altSplitPos: array[SplitKind, int] # alternative split positions @@ -69,14 +70,19 @@ template wr(x) = template goodCol(col): bool = col in 40..MaxLineLen -const splitters = {tkComma, tkSemicolon, tkParLe, tkParDotLe, - tkBracketLe, tkBracketLeColon, tkCurlyDotLe, - tkCurlyLe} +const + splitters = {tkComma, tkSemicolon, tkParLe, tkParDotLe, + tkBracketLe, tkBracketLeColon, tkCurlyDotLe, + tkCurlyLe} + sectionKeywords = {tkType, tkVar, tkConst, tkLet, tkUsing} template rememberSplit(kind) = if goodCol(em.col): em.altSplitPos[kind] = em.content.len +template moreIndent(em): int = + max(if em.doIndentMore > 0: em.indWidth*2 else: em.indWidth, 2) + proc softLinebreak(em: var Emitter, lit: string) = # XXX Use an algorithm that is outlined here: # https://llvm.org/devmtg/2013-04/jasper-slides.pdf @@ -85,12 +91,12 @@ proc softLinebreak(em: var Emitter, lit: string) = if em.lastTok in splitters: wr("\L") em.col = 0 - for i in 1..em.indentLevel+2: wr(" ") + for i in 1..em.indentLevel+moreIndent(em): wr(" ") else: # search backwards for a good split position: for a in em.altSplitPos: 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.content.insert(ws, a) break @@ -113,6 +119,10 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = wr lit var preventComment = false + if em.indWidth == 0 and tok.indent > 0: + # first indentation determines how many number of spaces to use: + em.indWidth = tok.indent + 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) @@ -127,9 +137,29 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = wr("\L") for i in 2..tok.line - em.lastLineNumber: wr("\L") em.col = 0 - for i in 1..tok.indent: + #[ we only correct the indentation if it is slightly off, + so that code like + + const splitters = {tkComma, tkSemicolon, tkParLe, tkParDotLe, + tkBracketLe, tkBracketLeColon, tkCurlyDotLe, + tkCurlyLe} + + is not touched. + ]# + when false: + if tok.indent > em.lastIndent and em.indWidth > 1 and (tok.indent mod em.indWidth) == 1: + em.indentLevel = 0 + while em.indentLevel < tok.indent-1: + inc em.indentLevel, em.indWidth + when false: + if em.indWidth != 0 and + abs(tok.indent - em.nested*em.indWidth) <= em.indWidth and + em.lastTok notin sectionKeywords: + em.indentLevel = em.nested*em.indWidth + for i in 1..em.indentLevel: wr(" ") em.fixedUntil = em.content.high + em.lastIndent = tok.indent case tok.tokType of tokKeywordLow..tokKeywordHigh: @@ -155,15 +185,19 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = wr(TokTypeToStr[tok.tokType]) wr(" ") rememberSplit(splitComma) - of tkParLe, tkParRi, tkBracketLe, - tkBracketRi, tkCurlyLe, tkCurlyRi, - tkBracketDotLe, tkBracketDotRi, - tkCurlyDotLe, tkCurlyDotRi, - tkParDotLe, tkParDotRi, - tkColonColon, tkDot, tkBracketLeColon: + of tkParDotLe, tkParLe, tkBracketDotLe, tkBracketLe, + tkCurlyLe, tkCurlyDotLe, tkBracketLeColon: + if tok.strongSpaceA > 0 and not em.endsInWhite: + wr(" ") + wr(TokTypeToStr[tok.tokType]) + rememberSplit(splitParLe) + of tkParRi, + tkBracketRi, tkCurlyRi, + tkBracketDotRi, + tkCurlyDotRi, + tkParDotRi, + tkColonColon, tkDot: wr(TokTypeToStr[tok.tokType]) - if tok.tokType in splitters: - rememberSplit(splitParLe) of tkEquals: if not em.endsInWhite: wr(" ") wr(TokTypeToStr[tok.tokType]) @@ -206,3 +240,13 @@ proc starWasExportMarker*(em: var Emitter) = setLen(em.content, em.content.len-3) em.content.add("*") 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(".}") diff --git a/compiler/parser.nim b/compiler/parser.nim index c0465b05e..9a9fed0cf 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -408,6 +408,8 @@ proc exprColonEqExpr(p: var TParser): PNode = proc exprList(p: var TParser, endTok: TTokType, result: PNode) = #| exprList = expr ^+ comma + when defined(nimpretty2): + inc p.em.doIndentMore getTok(p) optInd(p, result) # progress guaranteed @@ -417,6 +419,8 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) = if p.tok.tokType != tkComma: break getTok(p) optInd(p, a) + when defined(nimpretty2): + dec p.em.doIndentMore proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = 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) proc simpleExpr(p: var TParser, mode = pmNormal): PNode = + when defined(nimpretty2): + inc p.em.doIndentMore result = simpleExprAux(p, -1, mode) + when defined(nimpretty2): + dec p.em.doIndentMore proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = #| condExpr = expr colcom expr optInd @@ -912,8 +920,12 @@ proc parsePragma(p: var TParser): PNode = getTok(p) skipComment(p, a) optPar(p) - if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p) - else: parMessage(p, "expected '.}'") + if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: + when defined(nimpretty2): + curlyRiWasPragma(p.em) + getTok(p) + else: + parMessage(p, "expected '.}'") dec p.inPragma proc identVis(p: var TParser; allowDot=false): PNode = @@ -1000,6 +1012,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode = var a = parseIdentColonEquals(p, {}) addSon(result, a) if p.tok.tokType notin {tkComma, tkSemiColon}: break + when defined(nimpretty2): + commaWasSemicolon(p.em) getTok(p) skipComment(p, a) optPar(p) @@ -1034,6 +1048,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode = var a: PNode result = newNodeP(nkFormalParams, p) addSon(result, p.emptyNode) # return type + when defined(nimpretty2): + inc p.em.doIndentMore let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0 if hasParLe: getTok(p) @@ -1053,6 +1069,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode = break addSon(result, a) if p.tok.tokType notin {tkComma, tkSemiColon}: break + when defined(nimpretty2): + commaWasSemicolon(p.em) getTok(p) skipComment(p, a) optPar(p) @@ -1066,6 +1084,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode = elif not retColon and not hasParle: # Mark as "not there" in order to mark for deprecation in the semantic pass: result = p.emptyNode + when defined(nimpretty2): + dec p.em.doIndentMore proc optPragmas(p: var TParser): PNode = 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) addSon(result, a) if p.tok.tokType notin {tkComma, tkSemiColon}: break + when defined(nimpretty2): + commaWasSemicolon(p.em) getTok(p) skipComment(p, a) optPar(p) |