modulepaths.nim 3.4 KB

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