modulepaths.nim 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2017 Contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
  10. pathutils
  11. proc getModuleName*(conf: ConfigRef; n: PNode): string =
  12. # This returns a short relative module name without the nim extension
  13. # e.g. like "system", "importer" or "somepath/module"
  14. # The proc won't perform any checks that the path is actually valid
  15. case n.kind
  16. of nkStrLit, nkRStrLit, nkTripleStrLit:
  17. try:
  18. result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
  19. except ValueError:
  20. localError(conf, n.info, "invalid path: " & n.strVal)
  21. result = n.strVal
  22. of nkIdent:
  23. result = n.ident.s
  24. of nkSym:
  25. result = n.sym.name.s
  26. of nkInfix:
  27. let n0 = n[0]
  28. let n1 = n[1]
  29. when false:
  30. if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
  31. if n0.kind == nkIdent and n0.ident.s == "/":
  32. result = lookupPackage(n1[1], n[2])
  33. else:
  34. localError(n.info, "only '/' supported with $package notation")
  35. result = ""
  36. else:
  37. if n0.kind in nkIdentKinds:
  38. let ident = n0.getPIdent
  39. if ident != nil and ident.s[0] == '/':
  40. let modname = getModuleName(conf, n[2])
  41. # hacky way to implement 'x / y /../ z':
  42. result = getModuleName(conf, n1)
  43. result.add renderTree(n0, {renderNoComments}).replace(" ")
  44. result.add modname
  45. else:
  46. result = ""
  47. else:
  48. result = ""
  49. of nkPrefix:
  50. when false:
  51. if n[0].kind == nkIdent and n[0].ident.s == "$":
  52. result = lookupPackage(n[1], nil)
  53. else:
  54. discard
  55. # hacky way to implement 'x / y /../ z':
  56. result = renderTree(n, {renderNoComments}).replace(" ")
  57. of nkDotExpr:
  58. localError(conf, n.info, warnDeprecated, "using '.' instead of '/' in import paths is deprecated")
  59. result = renderTree(n, {renderNoComments}).replace(".", "/")
  60. of nkImportAs:
  61. result = getModuleName(conf, n[0])
  62. else:
  63. localError(conf, n.info, "invalid module name: '$1'" % n.renderTree)
  64. result = ""
  65. proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
  66. # This returns the full canonical path for a given module import
  67. let modulename = getModuleName(conf, n)
  68. let fullPath = findModule(conf, modulename, toFullPath(conf, n.info))
  69. if fullPath.isEmpty:
  70. if doLocalError:
  71. let m = if modulename.len > 0: modulename else: $n
  72. localError(conf, n.info, "cannot open file: " & m)
  73. result = InvalidFileIdx
  74. else:
  75. result = fileInfoIdx(conf, fullPath)
  76. proc mangleModuleName*(conf: ConfigRef; path: AbsoluteFile): string =
  77. ## Mangle a relative module path to avoid path and symbol collisions.
  78. ##
  79. ## Used by backends that need to generate intermediary files from Nim modules.
  80. ## This is needed because the compiler uses a flat cache file hierarchy.
  81. ##
  82. ## Example:
  83. ## `foo-#head/../bar` becomes `@foo-@hhead@s..@sbar`
  84. "@m" & relativeTo(path, conf.projectPath).string.multiReplace(
  85. {$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
  86. proc demangleModuleName*(path: string): string =
  87. ## Demangle a relative module path.
  88. result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"})