mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
nimpretty: check the rendered AST for wrong output (#23057)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user