summary refs log tree commit diff stats
path: root/compiler/modulepaths.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/modulepaths.nim')
-rw-r--r--compiler/modulepaths.nim105
1 files changed, 61 insertions, 44 deletions
diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim
index 6b9865677..c9e6060e5 100644
--- a/compiler/modulepaths.nim
+++ b/compiler/modulepaths.nim
@@ -1,31 +1,27 @@
 #
+#
+#           The Nim Compiler
+#        (c) Copyright 2017 Contributors
+#
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-import ast, renderer, gorgeimpl, strutils, msgs, options, idents, ospaths
+import ast, renderer, msgs, options, idents, lineinfos,
+  pathutils
 
-proc lookupPackage(pkg, subdir: PNode): string =
-  let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
-  case pkg.kind
-  of nkStrLit, nkRStrLit, nkTripleStrLit:
-    result = scriptableImport(pkg.strVal, sub, pkg.info)
-  of nkIdent:
-    result = scriptableImport(pkg.ident.s, sub, pkg.info)
-  else:
-    localError(pkg.info, "package name must be an identifier or string literal")
-    result = ""
+import std/[strutils, os]
 
-proc getModuleName*(n: PNode): string =
+proc getModuleName*(conf: ConfigRef; n: PNode): string =
   # This returns a short relative module name without the nim extension
   # e.g. like "system", "importer" or "somepath/module"
   # The proc won't perform any checks that the path is actually valid
   case n.kind
   of nkStrLit, nkRStrLit, nkTripleStrLit:
     try:
-      result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir)
+      result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
     except ValueError:
-      localError(n.info, "invalid path: " & n.strVal)
+      localError(conf, n.info, "invalid path: " & n.strVal)
       result = n.strVal
   of nkIdent:
     result = n.ident.s
@@ -34,45 +30,66 @@ proc getModuleName*(n: PNode): string =
   of nkInfix:
     let n0 = n[0]
     let n1 = n[1]
-    if n0.kind == nkIdent and n0.ident.id == getIdent("as").id:
-      # XXX hack ahead:
-      n.kind = nkImportAs
-      n.sons[0] = n.sons[1]
-      n.sons[1] = n.sons[2]
-      n.sons.setLen(2)
-      return getModuleName(n.sons[0])
-    if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
-      if n0.kind == nkIdent and n0.ident.s == "/":
-        result = lookupPackage(n1[1], n[2])
+    when false:
+      if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
+        if n0.kind == nkIdent and n0.ident.s == "/":
+          result = lookupPackage(n1[1], n[2])
+        else:
+          localError(n.info, "only '/' supported with $package notation")
+          result = ""
+    else:
+      if n0.kind in nkIdentKinds:
+        let ident = n0.getPIdent
+        if ident != nil and ident.s[0] == '/':
+          let modname = getModuleName(conf, n[2])
+          # hacky way to implement 'x / y /../ z':
+          result = getModuleName(conf, n1)
+          result.add renderTree(n0, {renderNoComments}).replace(" ")
+          result.add modname
+        else:
+          result = ""
       else:
-        localError(n.info, "only '/' supported with $package notation")
         result = ""
-    else:
-      # hacky way to implement 'x / y /../ z':
-      result = getModuleName(n1)
-      result.add renderTree(n0, {renderNoComments})
-      result.add getModuleName(n[2])
   of nkPrefix:
-    if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$":
-      result = lookupPackage(n[1], nil)
-    else:
-      # hacky way to implement 'x / y /../ z':
-      result = renderTree(n, {renderNoComments}).replace(" ")
+    when false:
+      if n[0].kind == nkIdent and n[0].ident.s == "$":
+        result = lookupPackage(n[1], nil)
+      else:
+        discard
+    # hacky way to implement 'x / y /../ z':
+    result = renderTree(n, {renderNoComments}).replace(" ")
   of nkDotExpr:
+    localError(conf, n.info, warnDeprecated, "using '.' instead of '/' in import paths is deprecated")
     result = renderTree(n, {renderNoComments}).replace(".", "/")
   of nkImportAs:
-    result = getModuleName(n.sons[0])
+    result = getModuleName(conf, n[0])
   else:
-    localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
+    localError(conf, n.info, "invalid module name: '$1'" % n.renderTree)
     result = ""
 
-proc checkModuleName*(n: PNode; doLocalError=true): int32 =
+proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
   # This returns the full canonical path for a given module import
-  let modulename = n.getModuleName
-  let fullPath = findModule(modulename, n.info.toFullPath)
-  if fullPath.len == 0:
+  let modulename = getModuleName(conf, n)
+  let fullPath = findModule(conf, modulename, toFullPath(conf, n.info))
+  if fullPath.isEmpty:
     if doLocalError:
-      localError(n.info, errCannotOpenFile, modulename)
-    result = InvalidFileIDX
+      let m = if modulename.len > 0: modulename else: $n
+      localError(conf, n.info, "cannot open file: " & m)
+    result = InvalidFileIdx
   else:
-    result = fullPath.fileInfoIdx
\ No newline at end of file
+    result = fileInfoIdx(conf, fullPath)
+
+proc mangleModuleName*(conf: ConfigRef; path: AbsoluteFile): string =
+  ## Mangle a relative module path to avoid path and symbol collisions.
+  ##
+  ## Used by backends that need to generate intermediary files from Nim modules.
+  ## This is needed because the compiler uses a flat cache file hierarchy.
+  ##
+  ## Example:
+  ## `foo-#head/../bar` becomes `@foo-@hhead@s..@sbar`
+  "@m" & relativeTo(path, conf.projectPath).string.multiReplace(
+    {$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
+
+proc demangleModuleName*(path: string): string =
+  ## Demangle a relative module path.
+  result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"})