From 6810a0e3e3f82ca40ca4fc51de820212dc90610d Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 29 Jul 2013 22:56:32 +0200 Subject: [PATCH] 'nimrod pretty' command: next steps --- compiler/main.nim | 11 +++- compiler/pretty.nim | 139 +++++++++++++++++++++++++++++++------------- 2 files changed, 107 insertions(+), 43 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index 047b3ff1d6..d8d8dc8db5 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -15,7 +15,8 @@ import wordrecg, sem, semdata, idents, passes, docgen, extccomp, cgen, jsgen, json, nversion, 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 @@ -162,11 +163,17 @@ proc commandEval(exp: string) = var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" evalNim(echoExp.parseString, makeStdinModule()) -proc CommandPretty = +proc CommandPrettyOld = var projectFile = addFileExt(mainCommandArg(), NimExt) var module = parseFile(projectFile.fileInfoIdx) if module != nil: renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt)) + +proc CommandPretty = + semanticPasses() + registerPass(prettyPass) + compileProject() + pretty.overwriteFiles() proc CommandScan = var f = addFileExt(mainCommandArg(), nimExt) diff --git a/compiler/pretty.nim b/compiler/pretty.nim index c205aaa7ed..92de96755d 100644 --- a/compiler/pretty.nim +++ b/compiler/pretty.nim @@ -11,7 +11,8 @@ ## to convert Nimrod code into a consistent style. import - os, options, ast, astalgo, msgs, ropes, idents, passes, importer + strutils, os, options, ast, astalgo, msgs, ropes, idents, passes, pegs, + intsets type TGen = object of TPassContext @@ -23,54 +24,110 @@ type dirty: bool fullpath: string -proc addSourceLine(fileIdx: int32, line: string) = - fileInfos[fileIdx].lines.add line +var + gSourceFiles: seq[TSourceFile] -proc sourceLine(i: TLineInfo): PRope = - if i.fileIndex < 0: return nil - - if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0: - try: - for line in lines(i.toFullPath): - addSourceLine i.fileIndex, line.string - except EIO: - discard - InternalAssert i.fileIndex < fileInfos.len - # can happen if the error points to EOF: - if i.line > fileInfos[i.fileIndex].lines.len: return nil +proc loadFile(info: TLineInfo) = + let i = info.fileIndex + if i >= gSourceFiles.len: + gSourceFiles.setLen(i) + gSourceFiles[i].lines = @[] + let path = info.toFullPath + gSourceFiles[i].fullpath = path + # we want to die here for EIO: + for line in lines(path): + gSourceFiles[i].lines.add(line) - 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) = - appf(gDotGraph, "$1 -> $2;$n", [toRope(importing), toRope(imported)]) - # s1 -> s2_4[label="[0-9]"]; - -proc addDotDependency(c: PPassContext, n: PNode): PNode = +proc beautifyName(s: string, k: TSymKind): string = + result = newStringOfCap(s.len) + var i = 0 + case k + 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 var g = PGen(c) case n.kind 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: - # we need to figure out whether the PType or the TType should become - # Type. The other then is either TypePtr/TypeRef or TypeDesc. + if s.id in cannotRename: return - of nkImportStmt: - for i in countup(0, sonsLen(n) - 1): - var imported = getModuleName(n.sons[i]) - addDependencyAux(g.module.name.s, imported) - of nkFromStmt, nkImportExceptStmt: - var imported = getModuleName(n.sons[0]) - addDependencyAux(g.module.name.s, imported) - of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: - for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i]) - else: - nil - -proc generateRefactorScript*(project: string) = - writeRope(ropef("digraph $1 {$n$2}$n", [ - toRope(changeFileExt(extractFileName(project), "")), gDotGraph]), - changeFileExt(project, "dot")) + let newName = beautifyName(s.name.s, n.sym.kind) + + loadFile(n.info) + + let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1] + var first = n.info.col.int - len(s.name.s) + if line[first] == '`': inc first + + if {sfImportc, sfExportc} * s.flags != {}: + # careful, we must ensure the resulting name still matches the external + # name: + if newName != s.name.s and newName != s.loc.r.ropeToStr: + Message(n.info, errGenerated, + "cannot rename $# to $# due to external name" % [s.name.s, newName]) + cannotRename.incl(s.id) + 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 ..