summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/c2nim/clex.nim8
-rwxr-xr-xcompiler/commands.nim10
-rwxr-xr-xcompiler/lexer.nim8
-rwxr-xr-xcompiler/main.nim2
-rwxr-xr-xcompiler/msgs.nim65
-rwxr-xr-xcompiler/nimrod.nim4
-rwxr-xr-xcompiler/options.nim7
-rwxr-xr-xcompiler/semstmts.nim2
-rwxr-xr-xcompiler/sigmatch.nim2
9 files changed, 61 insertions, 47 deletions
diff --git a/compiler/c2nim/clex.nim b/compiler/c2nim/clex.nim
index 5a67f9475..53f230b7b 100755
--- a/compiler/c2nim/clex.nim
+++ b/compiler/c2nim/clex.nim
@@ -97,7 +97,7 @@ type
     next*: ref TToken         # for C we need arbitrary look-ahead :-(
   
   TLexer* = object of TBaseLexer
-    filename*: string
+    fileIdx*: int32
     inDirective: bool
   
 proc getTok*(L: var TLexer, tok: var TToken)
@@ -117,7 +117,7 @@ proc fillToken(L: var TToken) =
   
 proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) = 
   openBaseLexer(lex, inputstream)
-  lex.filename = filename
+  lex.fileIdx = filename.fileInfoIdx
 
 proc closeLexer*(lex: var TLexer) = 
   inc(gLinesCompiled, lex.LineNumber)
@@ -127,13 +127,13 @@ proc getColumn*(L: TLexer): int =
   result = getColNumber(L, L.bufPos)
 
 proc getLineInfo*(L: TLexer): TLineInfo = 
-  result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
+  result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
 
 proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") = 
   msgs.GenericMessage(getLineInfo(L), msg, arg)
 
 proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = 
-  var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
+  var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
   msgs.GenericMessage(info, msg, arg)
 
 proc TokKindToStr*(k: TTokKind): string =
diff --git a/compiler/commands.nim b/compiler/commands.nim
index bce24c5da..f07361abe 100755
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -459,9 +459,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
     if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
     else: InvalidCmdLineOption(pass, switch, info)
   
-proc ProcessCommand(switch: string, pass: TCmdLinePass) = 
-  var
-    cmd, arg: string
-  var info = newLineInfo("command line", 1, 1)
-  splitSwitch(switch, cmd, arg, pass, info)
-  ProcessSwitch(cmd, arg, pass, info)
+proc ProcessCommand(switch: string, pass: TCmdLinePass) =
+  var cmd, arg: string
+  splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
+  processSwitch(cmd, arg, pass, gCmdLineInfo)
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 653644f8f..63a9bef87 100755
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -96,7 +96,7 @@ type
                               # documentation comments are here too
   
   TLexer* = object of TBaseLexer
-    filename*: string
+    fileIdx*: int32
     indentStack*: seq[int]    # the indentation stack
     dedent*: int              # counter for DED token generation
     indentAhead*: int         # if > 0 an indendation has already been read
@@ -198,7 +198,7 @@ proc fillToken(L: var TToken) =
 proc openLexer(lex: var TLexer, filename: string, inputstream: PLLStream) = 
   openBaseLexer(lex, inputstream)
   lex.indentStack = @[0]
-  lex.filename = filename
+  lex.fileIdx = filename.fileInfoIdx
   lex.indentAhead = - 1
   inc(lex.Linenumber, inputstream.lineOffset) 
 
@@ -210,13 +210,13 @@ proc getColumn(L: TLexer): int =
   result = getColNumber(L, L.bufPos)
 
 proc getLineInfo(L: TLexer): TLineInfo = 
-  result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
+  result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
 
 proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") = 
   msgs.Message(getLineInfo(L), msg, arg)
 
 proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = 
-  var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
+  var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
   msgs.Message(info, msg, arg)
 
 proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) = 
diff --git a/compiler/main.nim b/compiler/main.nim
index fd2908516..4d65f84bb 100755
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -176,7 +176,7 @@ proc CommandSuggest =
 
 proc wantMainModule =
   if gProjectFull.len == 0:
-    Fatal(newLineInfo("command line", 1, 1), errCommandExpectsFilename)
+    Fatal(gCmdLineInfo, errCommandExpectsFilename)
   
 proc MainCommand =
   appendStr(searchPaths, options.libpath)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 3090198ac..32afdee3b 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -8,7 +8,7 @@
 #
 
 import
-  options, strutils, os
+  options, strutils, os, tables
 
 type 
   TMsgKind* = enum 
@@ -384,6 +384,11 @@ const
 type 
   TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
   TNoteKinds* = set[TNoteKind]
+
+  TFileInfo*{.final.} = object 
+    fullPath*: string          # This is a canonical full filesystem path
+    projPath*: string          # This is relative to the project's root
+
   TLineInfo*{.final.} = object # This is designed to be as small as possible,
                                # because it is used
                                # in syntax nodes. We safe space here by using 
@@ -395,7 +400,37 @@ type
     
   ERecoverableError* = object of EInvalidValue
 
-proc newLineInfo*(filename: string, line, col: int): TLineInfo
+var
+  filenameToIndexTbl = initTable[string, int32]()
+  fileInfos: seq[TFileInfo] = @[]
+
+proc newFileInfo(fullPath, projPath: string): TFileInfo =
+  result.fullPath = fullPath
+  result.projPath = projPath
+
+proc fileInfoIdx*(filename: string): int32 =
+  var canonical = canonicalizePath(filename)
+
+  if filenameToIndexTbl.hasKey(canonical):
+    result = filenameToIndexTbl[canonical]
+  else:
+    result = fileInfos.len.int32
+    fileInfos.add(newFileInfo(canonical, canonical.shortenDir))
+    filenameToIndexTbl[canonical] = result
+
+proc newLineInfo*(filename: string, line, col: int): TLineInfo =
+  result.fileIndex = filename.fileInfoIdx
+  result.line = int16(line)
+  result.col = int16(col)
+
+proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
+  result.fileIndex = fileInfoIdx
+  result.line = int16(line)
+  result.col = int16(col)
+
+fileInfos.add(newFileInfo("command line", ""))
+var gCmdLineInfo* = newLineInfo(int32(0), 1, 1)
+
 proc raiseRecoverableError*() {.noinline, noreturn.} =
   raise newException(ERecoverableError, "")
 
@@ -423,9 +458,7 @@ proc UnknownLineInfo*(): TLineInfo =
   result.fileIndex = -1
 
 var 
-  filenames: seq[tuple[filename: string, fullpath: string]] = @[]
   msgContext: seq[TLineInfo] = @[]
-  gCmdLineInfo* = newLineInfo("command line", -1, -1)
 
 proc pushInfoContext*(info: TLineInfo) = 
   msgContext.add(info)
@@ -433,31 +466,13 @@ proc pushInfoContext*(info: TLineInfo) =
 proc popInfoContext*() = 
   setlen(msgContext, len(msgContext) - 1)
 
-proc includeFilename*(f: string): int = 
-  for i in countdown(high(filenames), low(filenames)): 
-    if filenames[i].filename == f:
-      return i
-  
-  result = len(filenames)
-  
-  var fullpath: string
-  try: fullpath = expandFilename(f)
-  except: fullpath = ""
-
-  filenames.add((filename: f, fullpath: fullpath))
-
-proc newLineInfo(filename: string, line, col: int): TLineInfo = 
-  result.fileIndex = includeFilename(filename)
-  result.line = int16(line)
-  result.col = int16(col)
-
-proc ToFilename*(info: TLineInfo): string = 
+proc ToFilename*(info: TLineInfo): string =
   if info.fileIndex < 0: result = "???"
-  else: result = filenames[info.fileIndex].filename
+  else: result = fileInfos[info.fileIndex].projPath
 
 proc toFullPath*(info: TLineInfo): string =
   if info.fileIndex < 0: result = "???"
-  else: result = filenames[info.fileIndex].fullpath
+  else: result = fileInfos[info.fileIndex].fullPath
   
 proc ToLinenumber*(info: TLineInfo): int {.inline.} = 
   result = info.line
diff --git a/compiler/nimrod.nim b/compiler/nimrod.nim
index 6a9ae690e..24dbc0617 100755
--- a/compiler/nimrod.nim
+++ b/compiler/nimrod.nim
@@ -70,14 +70,14 @@ proc HandleCmdLine() =
     ProcessCmdLine(passCmd1)
     if gProjectName != "":
       try:
-        gProjectFull = expandFilename(gProjectName)
+        gProjectFull = canonicalizePath(gProjectName)
       except EOS:
         gProjectFull = gProjectName
       var p = splitFile(gProjectFull)
       gProjectPath = p.dir
       gProjectName = p.name
     else:
-      gProjectPath = getCurrentDir()      
+      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
diff --git a/compiler/options.nim b/compiler/options.nim
index ea36e3c6a..bf01ea002 100755
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -138,14 +138,15 @@ proc getPrefixDir*(): string =
   ## gets the application directory
   result = SplitPath(getAppDir()).head
 
+proc canonicalizePath*(path: string): string =
+  result = path.expandFilename
+  when not FileSystemCaseSensitive: result = result.toLower
+
 proc shortenDir*(dir: string): string = 
   ## returns the interesting part of a dir
   var prefix = getPrefixDir() & dirSep
   if startsWith(dir, prefix): 
     return substr(dir, len(prefix))
-  prefix = getCurrentDir() & dirSep
-  if startsWith(dir, prefix): 
-    return substr(dir, len(prefix))
   prefix = gProjectPath & dirSep
   if startsWith(dir, prefix):
     return substr(dir, len(prefix))
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 2dbfa9497..3766841f1 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -796,7 +796,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
   addSon(result, n)
   for i in countup(0, sonsLen(n) - 1): 
     var f = getModuleFile(n.sons[i])
-    var fileIndex = includeFilename(f)
+    var fileIndex = f.fileInfoIdx
     if ContainsOrIncl(c.includedFiles, fileIndex): 
       GlobalError(n.info, errRecursiveDependencyX, f)
     addSon(result, semStmt(c, gIncludeFile(f)))
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index cd6cbe859..a6bde6e40 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -713,7 +713,7 @@ proc matches*(c: PContext, n: PNode, m: var TCandidate) =
 
   when false:
     if sfSystemModule notin c.module.flags:
-      if includeFilename("temp.nim") == c.module.info.fileIndex:
+      if fileInfoIdx("temp.nim") == c.module.info.fileIndex:
         echo "########################"
         echo m.call.renderTree
         for i in 1..m.call.len-1: