some progress on the nimpretty tool; still not ready

This commit is contained in:
Araq 2017-10-16 00:59:51 +02:00
commit 604a15c0aa
4 changed files with 79 additions and 17 deletions

View file

@ -129,6 +129,7 @@ type
when defined(nimpretty): when defined(nimpretty):
offsetA*, offsetB*: int # used for pretty printing so that literals offsetA*, offsetB*: int # used for pretty printing so that literals
# like 0b01 or r"\L" are unaffected # like 0b01 or r"\L" are unaffected
commentOffsetA*, commentOffsetB*: int
TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string) TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
TLexer* = object of TBaseLexer TLexer* = object of TBaseLexer
@ -144,6 +145,10 @@ type
when defined(nimsuggest): when defined(nimsuggest):
previousToken: TLineInfo previousToken: TLineInfo
when defined(nimpretty):
var
gIndentationWidth*: int
var gLinesCompiled*: int # all lines that have been compiled var gLinesCompiled*: int # all lines that have been compiled
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
@ -151,6 +156,8 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
when defined(nimpretty): when defined(nimpretty):
result.offsetA = tok.offsetA result.offsetA = tok.offsetA
result.offsetB = tok.offsetB result.offsetB = tok.offsetB
result.commentOffsetA = tok.commentOffsetA
result.commentOffsetB = tok.commentOffsetB
proc isKeyword*(kind: TTokType): bool = proc isKeyword*(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
@ -198,6 +205,9 @@ proc initToken*(L: var TToken) =
L.fNumber = 0.0 L.fNumber = 0.0
L.base = base10 L.base = base10
L.ident = nil L.ident = nil
when defined(nimpretty):
L.commentOffsetA = 0
L.commentOffsetB = 0
proc fillToken(L: var TToken) = proc fillToken(L: var TToken) =
L.tokType = tkInvalid L.tokType = tkInvalid
@ -208,6 +218,9 @@ proc fillToken(L: var TToken) =
L.fNumber = 0.0 L.fNumber = 0.0
L.base = base10 L.base = base10
L.ident = nil L.ident = nil
when defined(nimpretty):
L.commentOffsetA = 0
L.commentOffsetB = 0
proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream; proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream;
cache: IdentCache) = cache: IdentCache) =
@ -996,18 +1009,27 @@ proc skip(L: var TLexer, tok: var TToken) =
of '#': of '#':
# do not skip documentation comment: # do not skip documentation comment:
if buf[pos+1] == '#': break if buf[pos+1] == '#': break
when defined(nimpretty):
tok.commentOffsetA = L.offsetBase + pos
if buf[pos+1] == '[': if buf[pos+1] == '[':
skipMultiLineComment(L, tok, pos+2, false) skipMultiLineComment(L, tok, pos+2, false)
pos = L.bufpos pos = L.bufpos
buf = L.buf buf = L.buf
when defined(nimpretty):
tok.commentOffsetB = L.offsetBase + pos
else: else:
tokenBegin(tok, pos) tokenBegin(tok, pos)
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos) while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
tokenEndIgnore(tok, pos+1) tokenEndIgnore(tok, pos+1)
when defined(nimpretty):
tok.commentOffsetB = L.offsetBase + pos + 1
else: else:
break # EndOfFile also leaves the loop break # EndOfFile also leaves the loop
tokenEndPrevious(tok, pos-1) tokenEndPrevious(tok, pos-1)
L.bufpos = pos L.bufpos = pos
when defined(nimpretty):
if gIndentationWidth <= 0:
gIndentationWidth = tok.indent
proc rawGetTok*(L: var TLexer, tok: var TToken) = proc rawGetTok*(L: var TLexer, tok: var TToken) =
template atTokenEnd() {.dirty.} = template atTokenEnd() {.dirty.} =

View file

@ -500,6 +500,7 @@ type
fileIndex*: int32 fileIndex*: int32
when defined(nimpretty): when defined(nimpretty):
offsetA*, offsetB*: int offsetA*, offsetB*: int
commentOffsetA*, commentOffsetB*: int
TErrorOutput* = enum TErrorOutput* = enum
eStdOut eStdOut

View file

@ -37,6 +37,7 @@ type
inGenericParams: bool inGenericParams: bool
checkAnon: bool # we're in a context that can contain sfAnon checkAnon: bool # we're in a context that can contain sfAnon
inPragma: int inPragma: int
pendingNewlineCount: int
when defined(nimpretty): when defined(nimpretty):
origContent: string origContent: string
@ -62,9 +63,31 @@ proc renderDefinitionName*(s: PSym, noQuotes = false): string =
else: else:
result = '`' & x & '`' result = '`' & x & '`'
when not defined(nimpretty):
const
IndentWidth = 2
longIndentWid = IndentWidth * 2
else:
template IndentWidth: untyped = lexer.gIndentationWidth
template longIndentWid: untyped = IndentWidth() * 2
proc minmaxLine(n: PNode): (int, int) =
case n.kind
of nkTripleStrLit:
result = (n.info.line.int, n.info.line.int + countLines(n.strVal))
of nkCommentStmt:
result = (n.info.line.int, n.info.line.int + countLines(n.comment))
else:
result = (n.info.line.int, n.info.line.int)
for i in 0 ..< safeLen(n):
let (currMin, currMax) = minmaxLine(n[i])
if currMin < result[0]: result[0] = currMin
if currMax > result[1]: result[1] = currMax
proc lineDiff(a, b: PNode): int =
result = minmaxLine(b)[0] - minmaxLine(a)[1]
const const
IndentWidth = 2
longIndentWid = 4
MaxLineLen = 80 MaxLineLen = 80
LineCommentColumn = 30 LineCommentColumn = 30
@ -90,7 +113,8 @@ proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
proc addPendingNL(g: var TSrcGen) = proc addPendingNL(g: var TSrcGen) =
if g.pendingNL >= 0: if g.pendingNL >= 0:
addTok(g, tkSpaces, "\n" & spaces(g.pendingNL)) let newlines = repeat("\n", clamp(g.pendingNewlineCount, 1, 3))
addTok(g, tkSpaces, newlines & spaces(g.pendingNL))
g.lineLen = g.pendingNL g.lineLen = g.pendingNL
g.pendingNL = - 1 g.pendingNL = - 1
g.pendingWhitespace = -1 g.pendingWhitespace = -1
@ -114,11 +138,17 @@ proc putNL(g: var TSrcGen) =
proc optNL(g: var TSrcGen, indent: int) = proc optNL(g: var TSrcGen, indent: int) =
g.pendingNL = indent g.pendingNL = indent
g.lineLen = indent # BUGFIX g.lineLen = indent
g.pendingNewlineCount = 0
proc optNL(g: var TSrcGen) = proc optNL(g: var TSrcGen) =
optNL(g, g.indent) optNL(g, g.indent)
proc optNL(g: var TSrcGen; a, b: PNode) =
g.pendingNL = g.indent
g.lineLen = g.indent
g.pendingNewlineCount = lineDiff(a, b)
proc indentNL(g: var TSrcGen) = proc indentNL(g: var TSrcGen) =
inc(g.indent, IndentWidth) inc(g.indent, IndentWidth)
g.pendingNL = g.indent g.pendingNL = g.indent
@ -306,10 +336,14 @@ proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
proc atom(g: TSrcGen; n: PNode): string = proc atom(g: TSrcGen; n: PNode): string =
when defined(nimpretty): when defined(nimpretty):
let comment = if n.info.commentOffsetA < n.info.commentOffsetB:
" " & substr(g.origContent, n.info.commentOffsetA, n.info.commentOffsetB)
else:
""
if n.info.offsetA <= n.info.offsetB: if n.info.offsetA <= n.info.offsetB:
# for some constructed tokens this can not be the case and we're better # for some constructed tokens this can not be the case and we're better
# off to not mess with the offset then. # off to not mess with the offset then.
return substr(g.origContent, n.info.offsetA, n.info.offsetB) return substr(g.origContent, n.info.offsetA, n.info.offsetB) & comment
var f: float32 var f: float32
case n.kind case n.kind
of nkEmpty: result = "" of nkEmpty: result = ""
@ -577,12 +611,16 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
if n.kind == nkEmpty: return if n.kind == nkEmpty: return
if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}: if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
if doIndent: indentNL(g) if doIndent: indentNL(g)
for i in countup(0, sonsLen(n) - 1): let L = n.len
optNL(g) for i in 0 .. L-1:
if n.sons[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}: if i > 0:
gstmts(g, n.sons[i], c, doIndent=false) optNL(g, n[i-1], n[i])
else: else:
gsub(g, n.sons[i]) optNL(g)
if n[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
gstmts(g, n[i], c, doIndent=false)
else:
gsub(g, n[i])
gcoms(g) gcoms(g)
if doIndent: dedent(g) if doIndent: dedent(g)
else: else:
@ -1384,7 +1422,7 @@ proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
proc `$`*(n: PNode): string = n.renderTree proc `$`*(n: PNode): string = n.renderTree
proc renderModule*(n: PNode, filename: string, proc renderModule*(n: PNode, infile, outfile: string,
renderFlags: TRenderFlags = {}) = renderFlags: TRenderFlags = {}) =
var var
f: File f: File
@ -1392,9 +1430,9 @@ proc renderModule*(n: PNode, filename: string,
initSrcGen(g, renderFlags) initSrcGen(g, renderFlags)
when defined(nimpretty): when defined(nimpretty):
try: try:
g.origContent = readFile(filename) g.origContent = readFile(infile)
except IOError: except IOError:
rawMessage(errCannotOpenFile, filename) rawMessage(errCannotOpenFile, infile)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
gsub(g, n.sons[i]) gsub(g, n.sons[i])
@ -1406,11 +1444,11 @@ proc renderModule*(n: PNode, filename: string,
gcoms(g) gcoms(g)
if optStdout in gGlobalOptions: if optStdout in gGlobalOptions:
write(stdout, g.buf) write(stdout, g.buf)
elif open(f, filename, fmWrite): elif open(f, outfile, fmWrite):
write(f, g.buf) write(f, g.buf)
close(f) close(f)
else: else:
rawMessage(errCannotOpenFile, filename) rawMessage(errCannotOpenFile, outfile)
proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
initSrcGen(r, renderFlags) initSrcGen(r, renderFlags)

View file

@ -42,7 +42,8 @@ proc writeVersion() =
proc prettyPrint(infile: string) = proc prettyPrint(infile: string) =
let fileIdx = fileInfoIdx(infile) let fileIdx = fileInfoIdx(infile)
let tree = parseFile(fileIdx, newIdentCache()) let tree = parseFile(fileIdx, newIdentCache())
renderModule(tree, infile, {}) let outfile = changeFileExt(infile, ".pretty.nim")
renderModule(tree, infile, outfile, {})
proc main = proc main =
var infile: string var infile: string
@ -50,7 +51,7 @@ proc main =
for kind, key, val in getopt(): for kind, key, val in getopt():
case kind case kind
of cmdArgument: of cmdArgument:
infile = key infile = key.addFileExt(".nim")
of cmdLongoption, cmdShortOption: of cmdLongoption, cmdShortOption:
case normalize(key) case normalize(key)
of "help", "h": writeHelp() of "help", "h": writeHelp()