'nimrod pretty' command: next steps

This commit is contained in:
Araq 2013-07-29 22:56:32 +02:00
commit 6810a0e3e3
2 changed files with 107 additions and 43 deletions

View file

@ -15,7 +15,8 @@ import
wordrecg, sem, semdata, idents, passes, docgen, extccomp, wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, jsgen, json, nversion, cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, evals, types, idgen, platform, nimconf, importer, passaux, depends, evals, types, idgen,
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
pretty
from magicsys import SystemModule, resetSysTypes from magicsys import SystemModule, resetSysTypes
@ -162,11 +163,17 @@ proc commandEval(exp: string) =
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
evalNim(echoExp.parseString, makeStdinModule()) evalNim(echoExp.parseString, makeStdinModule())
proc CommandPretty = proc CommandPrettyOld =
var projectFile = addFileExt(mainCommandArg(), NimExt) var projectFile = addFileExt(mainCommandArg(), NimExt)
var module = parseFile(projectFile.fileInfoIdx) var module = parseFile(projectFile.fileInfoIdx)
if module != nil: if module != nil:
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt)) renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
proc CommandPretty =
semanticPasses()
registerPass(prettyPass)
compileProject()
pretty.overwriteFiles()
proc CommandScan = proc CommandScan =
var f = addFileExt(mainCommandArg(), nimExt) var f = addFileExt(mainCommandArg(), nimExt)

View file

@ -11,7 +11,8 @@
## to convert Nimrod code into a consistent style. ## to convert Nimrod code into a consistent style.
import import
os, options, ast, astalgo, msgs, ropes, idents, passes, importer strutils, os, options, ast, astalgo, msgs, ropes, idents, passes, pegs,
intsets
type type
TGen = object of TPassContext TGen = object of TPassContext
@ -23,54 +24,110 @@ type
dirty: bool dirty: bool
fullpath: string fullpath: string
proc addSourceLine(fileIdx: int32, line: string) = var
fileInfos[fileIdx].lines.add line gSourceFiles: seq[TSourceFile]
proc sourceLine(i: TLineInfo): PRope = proc loadFile(info: TLineInfo) =
if i.fileIndex < 0: return nil let i = info.fileIndex
if i >= gSourceFiles.len:
if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0: gSourceFiles.setLen(i)
try: gSourceFiles[i].lines = @[]
for line in lines(i.toFullPath): let path = info.toFullPath
addSourceLine i.fileIndex, line.string gSourceFiles[i].fullpath = path
except EIO: # we want to die here for EIO:
discard for line in lines(path):
InternalAssert i.fileIndex < fileInfos.len gSourceFiles[i].lines.add(line)
# can happen if the error points to EOF:
if i.line > fileInfos[i.fileIndex].lines.len: return nil
result = fileInfos[i.fileIndex].lines[i.line-1] proc overwriteFiles*() =
for i in 0 .. high(gSourceFiles):
if not gSourceFiles[i].dirty: continue
var f = open(gSourceFiles[i].fullpath.changeFileExt(".pretty.nim"), fmWrite)
for line in gSourceFiles[i].lines:
f.writeln(line)
f.close
proc addDependencyAux(importing, imported: string) = proc beautifyName(s: string, k: TSymKind): string =
appf(gDotGraph, "$1 -> $2;$n", [toRope(importing), toRope(imported)]) result = newStringOfCap(s.len)
# s1 -> s2_4[label="[0-9]"]; var i = 0
case k
proc addDotDependency(c: PPassContext, n: PNode): PNode = of skType, skGenericParam:
# skip leading 'T'
if s[0] == 'T' and s[1] in {'A'..'Z'}:
i = 1
result.add toUpper(s[i])
of skConst, skEnumField:
# for 'const' we keep how it's spelt; either upper case or lower case:
result.add s[0]
else:
result.add toLower(s[0])
inc i
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
while i < s.len:
if s[i] == '_':
inc i
result.add toUpper(s[i])
elif allUpper:
result.add toLower(s[i])
else:
result.add s[i]
inc i
const
Letters = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen(line: string, start: int): int =
while start+result < line.len and line[start+result] in Letters:
inc result
proc differ(line: string, a, b: int, x: string): bool =
var j = 0
for i in a..b:
if line[i] != x[j]: return true
inc j
return false
var cannotRename = initIntSet()
proc processSym(c: PPassContext, n: PNode): PNode =
result = n result = n
var g = PGen(c) var g = PGen(c)
case n.kind case n.kind
of nkSym: of nkSym:
if n.info.fileIndex < 0: return
let s = n.sym
# operators stay as they are:
if s.kind == skTemp or s.name.s[0] notin Letters: return
of nkTypeSection: if s.id in cannotRename: return
# we need to figure out whether the PType or the TType should become
# Type. The other then is either TypePtr/TypeRef or TypeDesc.
of nkImportStmt: let newName = beautifyName(s.name.s, n.sym.kind)
for i in countup(0, sonsLen(n) - 1):
var imported = getModuleName(n.sons[i]) loadFile(n.info)
addDependencyAux(g.module.name.s, imported)
of nkFromStmt, nkImportExceptStmt: let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
var imported = getModuleName(n.sons[0]) var first = n.info.col.int - len(s.name.s)
addDependencyAux(g.module.name.s, imported) if line[first] == '`': inc first
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i]) if {sfImportc, sfExportc} * s.flags != {}:
else: # careful, we must ensure the resulting name still matches the external
nil # name:
if newName != s.name.s and newName != s.loc.r.ropeToStr:
proc generateRefactorScript*(project: string) = Message(n.info, errGenerated,
writeRope(ropef("digraph $1 {$n$2}$n", [ "cannot rename $# to $# due to external name" % [s.name.s, newName])
toRope(changeFileExt(extractFileName(project), "")), gDotGraph]), cannotRename.incl(s.id)
changeFileExt(project, "dot")) return
let last = first+identLen(line, first)-1
if last-first+1 != newName.len or differ(line, first, last, newName):
var x = line.subStr(0, first-1) & newName & line.substr(last+1)
# the WinAPI module is full of 'TX = X' which after the substitution
# becomes 'X = X'. We remove those lines:
if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
x = ""
system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
gSourceFiles[n.info.fileIndex].dirty = true
else:
for i in 0 .. <n.safeLen:
discard processSym(c, n.sons[i])
proc myOpen(module: PSym): PPassContext = proc myOpen(module: PSym): PPassContext =
var g: PGen var g: PGen
@ -78,5 +135,5 @@ proc myOpen(module: PSym): PPassContext =
g.module = module g.module = module
result = g result = g
const prettyPass* = makePass(open = myOpen, process = addDotDependency) const prettyPass* = makePass(open = myOpen, process = processSym)