nimpretty: check the rendered AST for wrong output (#23057)

This commit is contained in:
Andreas Rumpf
2023-12-13 10:39:10 +01:00
committed by GitHub
parent 7e1ea50bc3
commit cd4ecddb30
3 changed files with 55 additions and 14 deletions

View File

@@ -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
@@ -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

View File

@@ -155,8 +155,6 @@ proc openParser*(p: var Parser, filename: AbsoluteFile, inputStream: PLLStream,
proc closeParser*(p: var Parser) =
## Close a parser, freeing up its resources.
closeLexer(p.lex)
when defined(nimpretty):
closeEmitter(p.em)
proc parMessage(p: Parser, msg: TMsgKind, arg = "") =
## Produce and emit the parser message `arg` to output.

View File

@@ -12,7 +12,7 @@
when not defined(nimpretty):
{.error: "This needs to be compiled with --define:nimPretty".}
import ../compiler / [idents, msgs, syntaxes, options, pathutils, layouter]
import ../compiler / [idents, llstream, ast, msgs, syntaxes, options, pathutils, layouter]
import parseopt, strutils, os, sequtils
@@ -48,6 +48,42 @@ type
indWidth*: Natural
maxLineLen*: Positive
proc goodEnough(a, b: PNode): bool =
if a.kind == b.kind and a.safeLen == b.safeLen:
case a.kind
of nkNone, nkEmpty, nkNilLit: result = true
of nkIdent: result = a.ident.id == b.ident.id
of nkSym: result = a.sym == b.sym
of nkType: result = true
of nkCharLit, nkIntLit..nkInt64Lit, nkUIntLit..nkUInt64Lit:
result = a.intVal == b.intVal
of nkFloatLit..nkFloat128Lit:
result = a.floatVal == b.floatVal
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = a.strVal == b.strVal
else:
for i in 0 ..< a.len:
if not goodEnough(a[i], b[i]): return false
return true
elif a.kind == nkStmtList and a.len == 1:
result = goodEnough(a[0], b)
elif b.kind == nkStmtList and b.len == 1:
result = goodEnough(a, b[0])
else:
result = false
proc finalCheck(content: string; origAst: PNode): bool {.nimcall.} =
var conf = newConfigRef()
let oldErrors = conf.errorCounter
var parser: Parser
parser.em.indWidth = 2
let fileIdx = fileInfoIdx(conf, AbsoluteFile "nimpretty_bug.nim")
openParser(parser, fileIdx, llStreamOpen(content), newIdentCache(), conf)
let newAst = parseAll(parser)
closeParser(parser)
result = conf.errorCounter == oldErrors # and goodEnough(newAst, origAst)
proc prettyPrint*(infile, outfile: string, opt: PrettyOptions) =
var conf = newConfigRef()
let fileIdx = fileInfoIdx(conf, AbsoluteFile infile)
@@ -58,8 +94,10 @@ proc prettyPrint*(infile, outfile: string, opt: PrettyOptions) =
parser.em.indWidth = opt.indWidth
if setupParser(parser, fileIdx, newIdentCache(), conf):
parser.em.maxLineLen = opt.maxLineLen
discard parseAll(parser)
let fullAst = parseAll(parser)
closeParser(parser)
when defined(nimpretty):
closeEmitter(parser.em, fullAst, finalCheck)
proc main =
var outfile, outdir: string