diff options
Diffstat (limited to 'compiler/layouter.nim')
-rw-r--r-- | compiler/layouter.nim | 77 |
1 files changed, 45 insertions, 32 deletions
diff --git a/compiler/layouter.nim b/compiler/layouter.nim index e137ee8a0..0121b1185 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -9,7 +9,7 @@ ## Layouter for nimpretty. -import idents, lexer, lineinfos, llstream, options, msgs, strutils, pathutils +import idents, lexer, ast, lineinfos, llstream, options, msgs, strutils, pathutils const MinLineLen = 15 @@ -35,7 +35,7 @@ type Emitter* = object config: ConfigRef fid: FileIndex - lastTok: TTokType + lastTok: TokType inquote, lastTokWasTerse: bool semicolons: SemicolonKind col, lastLineNumber, lineSpan, indentLevel, indWidth*, inSection: int @@ -243,23 +243,28 @@ proc renderTokens*(em: var Emitter): string = return content -proc writeOut*(em: Emitter, content: string) = +type + FinalCheck = proc (content: string; origAst: PNode): bool {.nimcall.} + +proc writeOut*(em: Emitter; content: string; origAst: PNode; check: FinalCheck) = ## Write to disk let outFile = em.config.absOutFile if fileExists(outFile) and readFile(outFile.string) == content: discard "do nothing, see #9499" return - var f = llStreamOpen(outFile, fmWrite) - if f == nil: - rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string) - return - f.llStreamWrite content - llStreamClose(f) -proc closeEmitter*(em: var Emitter) = + if check(content, origAst): + var f = llStreamOpen(outFile, fmWrite) + if f == nil: + rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string) + return + f.llStreamWrite content + llStreamClose(f) + +proc closeEmitter*(em: var Emitter; origAst: PNode; check: FinalCheck) = ## Renders emitter tokens and write to a file let content = renderTokens(em) - em.writeOut(content) + em.writeOut(content, origAst, check) proc wr(em: var Emitter; x: string; lt: LayoutToken) = em.tokens.add x @@ -327,7 +332,7 @@ const splitters = openPars + {tkComma, tkSemiColon} # do not add 'tkColon' here! oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, - tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor} + tkIsnot, tkNot, tkOf, tkAs, tkFrom, tkDotDot, tkAnd, tkOr, tkXor} template goodCol(col): bool = col >= em.maxLineLen div 2 @@ -402,7 +407,7 @@ proc endsInAlpha(em: Emitter): bool = while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection}: dec(i) result = if i >= 0: em.tokens[i].lastChar in SymChars+{'_'} else: false -proc emitComment(em: var Emitter; tok: TToken; dontIndent: bool) = +proc emitComment(em: var Emitter; tok: Token; dontIndent: bool) = var col = em.col let lit = strip fileSection(em.config, em.fid, tok.commentOffsetA, tok.commentOffsetB) em.lineSpan = countNewlines(lit) @@ -417,7 +422,7 @@ proc emitComment(em: var Emitter; tok: TToken; dontIndent: bool) = inc col emitMultilineComment(em, lit, col, dontIndent) -proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = +proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = template wasExportMarker(em): bool = em.kinds.len > 0 and em.kinds[^1] == ltExportMarker @@ -452,6 +457,9 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = if tok.tokType in openPars and tok.indent > em.indentStack[^1]: while em.indentStack[^1] < tok.indent: em.indentStack.add(em.indentStack[^1] + em.indWidth) + while em.indentStack[^1] > tok.indent: + discard em.indentStack.pop() + # aka: we are in an expression context: let alignment = max(tok.indent - em.indentStack[^1], 0) em.indentLevel = alignment + em.indentStack.high * em.indWidth @@ -491,7 +499,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = wrSpace em if not em.inquote: - wr(em, TokTypeToStr[tok.tokType], ltKeyword) + wr(em, $tok.tokType, ltKeyword) if tok.tokType in {tkAnd, tkOr, tkIn, tkNotin}: rememberSplit(splitIn) wrSpace em @@ -500,31 +508,32 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = wr(em, tok.ident.s, ltIdent) of tkColon: - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) wrSpace em of tkSemiColon, tkComma: - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) rememberSplit(splitComma) wrSpace em of openPars: - if tok.strongSpaceA > 0 and not em.endsInWhite and + if tsLeading in tok.spacing and not em.endsInWhite and (not em.wasExportMarker or tok.tokType == tkCurlyDotLe): wrSpace em - wr(em, TokTypeToStr[tok.tokType], ltSomeParLe) - rememberSplit(splitParLe) + wr(em, $tok.tokType, ltSomeParLe) + if tok.tokType != tkCurlyDotLe: + rememberSplit(splitParLe) of closedPars: - wr(em, TokTypeToStr[tok.tokType], ltSomeParRi) + wr(em, $tok.tokType, ltSomeParRi) of tkColonColon: - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) of tkDot: lastTokWasTerse = true - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) of tkEquals: if not em.inquote and not em.endsInWhite: wrSpace(em) - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) if not em.inquote: wrSpace(em) of tkOpr, tkDotDot: - if em.inquote or ((tok.strongSpaceA == 0 and tok.strongSpaceB == 0) and + if em.inquote or (tok.spacing == {} and tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]): # bug #9504: remember to not spacify a keyword: lastTokWasTerse = true @@ -534,24 +543,28 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = if not em.endsInWhite: wrSpace(em) wr(em, tok.ident.s, ltOpr) template isUnary(tok): bool = - tok.strongSpaceB == 0 and tok.strongSpaceA > 0 + tok.spacing == {tsLeading} if not isUnary(tok): rememberSplit(splitBinary) wrSpace(em) of tkAccent: if not em.inquote and endsInAlpha(em): wrSpace(em) - wr(em, TokTypeToStr[tok.tokType], ltOther) + wr(em, $tok.tokType, ltOther) em.inquote = not em.inquote of tkComment: if not preventComment: emitComment(em, tok, dontIndent = false) of tkIntLit..tkStrLit, tkRStrLit, tkTripleStrLit, tkGStrLit, tkGTripleStrLit, tkCharLit: - let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB) - if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em) - em.lineSpan = countNewlines(lit) - if em.lineSpan > 0: calcCol(em, lit) - wr em, lit, ltLit + if not em.inquote: + let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB) + if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em) + em.lineSpan = countNewlines(lit) + if em.lineSpan > 0: calcCol(em, lit) + wr em, lit, ltLit + else: + if endsInAlpha(em): wrSpace(em) + wr em, tok.literal, ltLit of tkEof: discard else: let lit = if tok.ident != nil: tok.ident.s else: tok.literal |