mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
* Refactor and doc package handling, module name mangling * Consolidate, de-duplicate and extend package handling * Alter how duplicate module names of a package are handled * Alter how module names are mangled * Fix crash when another package is named 'stdlib' (test case added) * Doc what defines a package in the manual Modules with duplicate names within a package used to be given 'fake' packages to resolve conflicts. That prevented the ability to discern if a module belonged to the current project package or a foreign package. They now have the proper package owner and the names are mangled in a consistent manner to prevent codegen clashes. All module names are now mangled the same. Stdlib was treated special before, but now it is same as any other package. This fixes a crash when a foreign package is named 'stdlib'. Module mangling is altered for both file paths and symbols used by the backends. Removed an unused module name to package mapping that may have been intended for IC. The mapping was removed because it wasn't being used and was complicating the issue of package modules with duplicate names not having the proper package owner assigned. * Fix some tests * Refactor `packagehandling` * Remove `packagehandling.withPackageName` and its uses * Move module path mangling from `packagehandling` to `modulepaths` * Move `options.toRodFile` to `ic` to break import cycle * Changed import style to match preferred style Co-authored-by: quantimnot <quantimnot@users.noreply.github.com>
87 lines
3.1 KiB
Nim
87 lines
3.1 KiB
Nim
#
|
|
#
|
|
# The Nim Compiler
|
|
# (c) Copyright 2017 Contributors
|
|
#
|
|
# See the file "copying.txt", included in this
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
|
|
pathutils
|
|
|
|
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(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
|
|
except ValueError:
|
|
localError(conf, n.info, "invalid path: " & n.strVal)
|
|
result = n.strVal
|
|
of nkIdent:
|
|
result = n.ident.s
|
|
of nkSym:
|
|
result = n.sym.name.s
|
|
of nkInfix:
|
|
let n0 = n[0]
|
|
let n1 = n[1]
|
|
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:
|
|
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
|
|
of nkPrefix:
|
|
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(conf, n[0])
|
|
else:
|
|
localError(conf, n.info, "invalid module name: '$1'" % n.renderTree)
|
|
result = ""
|
|
|
|
proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
|
|
# This returns the full canonical path for a given module import
|
|
let modulename = getModuleName(conf, n)
|
|
let fullPath = findModule(conf, modulename, toFullPath(conf, n.info))
|
|
if fullPath.isEmpty:
|
|
if doLocalError:
|
|
let m = if modulename.len > 0: modulename else: $n
|
|
localError(conf, n.info, "cannot open file: " & m)
|
|
result = InvalidFileIdx
|
|
else:
|
|
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": ":"})
|