summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/cgen.nim6
-rw-r--r--compiler/lookups.nim27
-rw-r--r--compiler/nim.nimrod.cfg1
-rw-r--r--compiler/nimfix.nim97
-rw-r--r--compiler/nimfix.nim.cfg16
-rw-r--r--compiler/prettybase.nim11
-rw-r--r--compiler/sigmatch.nim3
-rw-r--r--compiler/vmgen.nim5
-rw-r--r--config/nim.cfg4
9 files changed, 159 insertions, 11 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 7c694f245..490aeec4b 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -139,7 +139,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
     if i - 1 >= start: 
       app(result, substr(frmt, start, i - 1))
 
-const compileTimeRopeFmt = not defined(booting)
+const compileTimeRopeFmt = false
 
 when compileTimeRopeFmt:
   import macros
@@ -186,7 +186,7 @@ when compileTimeRopeFmt:
         while s[i] in IdentChars: inc i
         yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
         start = i
-      else: nil
+      else: discard
 
       while i < length:
         if s[i] != '$' and s[i] != '#': inc i
@@ -201,7 +201,7 @@ when compileTimeRopeFmt:
     ## the compilation of nimrod itself or will the macro execution time
     ## offset the gains?
     result = newCall(bindSym"ropeConcat")
-    for frag in fmtStringFragments(fmt.strVal):
+    for frag in fmtStringFragments(fmt):
       case frag.kind
       of ffSym:
         result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 9bad9de91..466ac824a 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -171,7 +171,7 @@ proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
   if fn.kind notin OverloadableSyms: 
     internalError(fn.info, "addOverloadableSymAt")
     return
-  var check = strTableGet(scope.symbols, fn.name)
+  let check = strTableGet(scope.symbols, fn.name)
   if check != nil and check.kind notin OverloadableSyms: 
     wrongRedefinition(fn.info, fn.name.s)
   else:
@@ -187,12 +187,32 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
   addOverloadableSymAt(scope, sym)
   addInterfaceDeclAux(c, sym)
 
+when defined(nimfix):
+  import strutils
+
+  # when we cannot find the identifier, retry with a changed identifer:
+  proc altSpelling(x: PIdent): PIdent =
+    case x.s[0]
+    of 'A'..'Z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
+    of 'a'..'z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
+    else: result = x
+
+  template fixSpelling(n: PNode; ident: PIdent; op: expr) =
+    let alt = ident.altSpelling
+    result = op(c, alt).skipAlias(n)
+    if result != nil:
+      prettybase.replaceDeprecated(n.info, ident, alt)
+      return result
+else:
+  template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard
+
 proc lookUp*(c: PContext, n: PNode): PSym = 
   # Looks up a symbol. Generates an error in case of nil.
   case n.kind
   of nkIdent:
     result = searchInScopes(c, n.ident).skipAlias(n)
     if result == nil:
+      fixSpelling(n, n.ident, searchInScopes)
       localError(n.info, errUndeclaredIdentifier, n.ident.s)
       result = errorSym(c, n)
   of nkSym:
@@ -201,6 +221,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
     var ident = considerQuotedIdent(n)
     result = searchInScopes(c, ident).skipAlias(n)
     if result == nil:
+      fixSpelling(n, ident, searchInScopes)
       localError(n.info, errUndeclaredIdentifier, ident.s)
       result = errorSym(c, n)
   else:
@@ -214,12 +235,13 @@ type
   TLookupFlag* = enum 
     checkAmbiguity, checkUndeclared
 
-proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym = 
+proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
   case n.kind
   of nkIdent, nkAccQuoted:
     var ident = considerQuotedIdent(n)
     result = searchInScopes(c, ident).skipAlias(n)
     if result == nil and checkUndeclared in flags:
+      fixSpelling(n, ident, searchInScopes)
       localError(n.info, errUndeclaredIdentifier, ident.s)
       result = errorSym(c, n)
     elif checkAmbiguity in flags and result != nil and
@@ -244,6 +266,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
         else:
           result = strTableGet(m.tab, ident).skipAlias(n)
         if result == nil and checkUndeclared in flags:
+          fixSpelling(n.sons[1], ident, searchInScopes)
           localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
           result = errorSym(c, n.sons[1])
       elif n.sons[1].kind == nkSym:
diff --git a/compiler/nim.nimrod.cfg b/compiler/nim.nimrod.cfg
index c9e4b248b..5a892bad0 100644
--- a/compiler/nim.nimrod.cfg
+++ b/compiler/nim.nimrod.cfg
@@ -21,3 +21,4 @@ define:useStdoutAsStdmsg
 
 cs:partial
 #define:useNodeIds
+symbol:nimfix
diff --git a/compiler/nimfix.nim b/compiler/nimfix.nim
new file mode 100644
index 000000000..3fbf27e54
--- /dev/null
+++ b/compiler/nimfix.nim
@@ -0,0 +1,97 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2014 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
+
+import strutils, os, parseopt
+import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
+  extccomp, condsyms
+
+const Usage = """
+Nimfix - Tool to patch Nim code
+Usage:
+  nimfix [options] projectflie.nim
+
+Options:
+  --overwriteFiles:on|off          overwrite the original nim files.
+                                   DEFAULT is ON!
+  --checkExtern:on|off             style check also extern names
+  --styleCheck:none|confirm|auto   performs style checking for identifiers
+                                   and suggests an alternative spelling. If
+                                   'auto', it automatically corrects the
+                                   spelling. If 'confirm' it asks the user.
+
+In addition, all command line options of Nim are supported.
+"""
+
+proc mainCommand =
+  #msgs.gErrorMax = high(int)  # do not stop after first error
+  registerPass verbosePass
+  registerPass semPass
+  registerPass prettyPass
+  gCmd = cmdPretty
+  compileProject()
+  pretty.overwriteFiles()
+
+proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
+  var p = parseopt.initOptParser(cmd)
+  var argsCount = 0
+  while true: 
+    parseopt.next(p)
+    case p.kind
+    of cmdEnd: break 
+    of cmdLongoption, cmdShortOption: 
+      case p.key.normalize
+      of "overwritefiles":
+        case p.val.normalize
+        of "on": gOverWrite = true
+        of "off": gOverWrite = false
+        else: localError(gCmdLineInfo, errOnOrOffExpected)
+      of "checkextern":
+        case p.val.normalize
+        of "on": gCheckExtern = true
+        of "off": gCheckExtern = false
+        else: localError(gCmdLineInfo, errOnOrOffExpected)
+      of "stylecheck": 
+        case p.val.normalize
+        of "none": gStyleCheck = StyleCheck.None
+        of "confirm": gStyleCheck = StyleCheck.Confirm
+        of "auto": gStyleCheck = StyleCheck.Auto
+        else: localError(gCmdLineInfo, errGenerated,
+                         "'none', 'confirm' or 'auto' expected")
+      else:
+        processSwitch(pass, p)
+    of cmdArgument:
+      if processArgument(pass, p, argsCount): break
+
+proc handleCmdLine() =
+  if paramCount() == 0:
+    stdout.writeln(Usage)
+  else:
+    processCmdLine(passCmd1, "")
+    if gProjectName != "":
+      try:
+        gProjectFull = canonicalizePath(gProjectName)
+      except OSError:
+        gProjectFull = gProjectName
+      var p = splitFile(gProjectFull)
+      gProjectPath = p.dir
+      gProjectName = p.name
+    else:
+      gProjectPath = getCurrentDir()
+    loadConfigs(DefaultConfig) # load all config files
+    # now process command line arguments again, because some options in the
+    # command line can overwite the config file's settings
+    extccomp.initVars()
+    processCmdLine(passCmd2, "")
+    mainCommand()
+
+condsyms.initDefines()
+defineSymbol "nimfix"
+handleCmdline()
diff --git a/compiler/nimfix.nim.cfg b/compiler/nimfix.nim.cfg
new file mode 100644
index 000000000..61df6742e
--- /dev/null
+++ b/compiler/nimfix.nim.cfg
@@ -0,0 +1,16 @@
+# Special configuration file for the Nim project
+# gc:markAndSweep
+
+hint[XDeclaredButNotUsed]:off
+path:"$projectPath/.."
+
+path:"$lib/packages/docutils"
+
+define:useStdoutAsStdmsg
+symbol:nimfix
+define:nimfix
+
+cs:partial
+#define:useNodeIds
+define:booting
+define:noDocgen
diff --git a/compiler/prettybase.nim b/compiler/prettybase.nim
index baf2484e4..dca6bcdaa 100644
--- a/compiler/prettybase.nim
+++ b/compiler/prettybase.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-import ast, msgs, strutils
+import ast, msgs, strutils, idents
 
 type
   TSourceFile* = object
@@ -41,7 +41,7 @@ proc differ*(line: string, a, b: int, x: string): bool =
   let y = line[a..b]
   result = cmpIgnoreStyle(y, x) == 0 and y != x
 
-proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
+proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
   loadFile(info)
 
   let line = gSourceFiles[info.fileIndex].lines[info.line-1]
@@ -53,7 +53,10 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
   if line[first] == '`': inc first
   
   let last = first+identLen(line, first)-1
-  if cmpIgnoreStyle(line[first..last], oldSym.name.s) == 0:
-    var x = line.substr(0, first-1) & newSym.name.s & line.substr(last+1)    
+  if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
+    var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)    
     system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
     gSourceFiles[info.fileIndex].dirty = true
+
+proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
+  replaceDeprecated(info, oldSym.name, newSym.name)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 26277eb50..d7b397af6 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1482,6 +1482,9 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
 
 include suggest
 
+when not declared(tests):
+  template tests(s: stmt) {.immediate.} = discard
+
 tests:
   var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
   
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 718c07243..3921a69fe 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1057,7 +1057,7 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
   # nkAddr we must not use 'unneededIndirection', but for deref we use it.
   if not isAddr and unneededIndirection(n.sons[0]):
     gen(c, n.sons[0], dest, newflags)
-  elif isGlobal(n.sons[0]):
+  elif isAddr and isGlobal(n.sons[0]):
     gen(c, n.sons[0], dest, flags+{gfAddrOf})
   else:
     let tmp = c.genx(n.sons[0], newflags)
@@ -1137,6 +1137,9 @@ proc isTemp(c: PCtx; dest: TDest): bool =
 template needsAdditionalCopy(n): expr =
   not c.isTemp(dest) and not fitsRegister(n.typ)
 
+proc skipDeref(n: PNode): PNode =
+  result = if n.kind in {nkDerefExpr, nkHiddenDeref}: n.sons[0] else: n
+
 proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
                        dest, idx, value: TRegister) =
   # opcLdObj et al really means "load address". We sometimes have to create a
diff --git a/config/nim.cfg b/config/nim.cfg
index 6d56bba2c..b0a1ff81b 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -13,7 +13,9 @@ cc = gcc
 arm.linux.gcc.exe = "arm-linux-gcc"
 arm.linux.gcc.linkerexe = "arm-linux-gcc"
 
-cs:partial
+@if not nimfix:
+  cs:partial
+@end
 
 path="$lib/core"
 path="$lib/pure"