### The Nim Compiler# (c) Copyright 2017 Contributors## See the file "copying.txt", included in this# distribution, for details about the copyright.#importast,renderer,strutils,msgs,options,idents,os,lineinfos,pathutils,nimblecmdwhenfalse:constconsiderParentDirs=notdefined(noParentProjects)considerNimbleDirs=notdefined(noNimbleDirs)procfindInNimbleDir(pkg,subdir,dir:string):string=varbest=""varbestv=""fork,pinos.walkDir(dir,relative=true):ifk==pcDirandp.len>pkg.len+1andp[pkg.len]=='-'andp.startsWith(pkg):let(_, a) = getPathVersion(p)ifbestv.len==0orbestv<a:bestv=abest=dir/pifbest.len>0:varf:Fileifopen(f,best/changeFileExt(pkg,".nimble-link")):# the second line contains what we're interested in, see:# https://github.com/nim-lang/nimble#nimble-linkvaroverride=""discardreadLine(f,override)discardreadLine(f,override)close(f)ifnotoverride.isAbsolute():best=best/overrideelse:best=overrideletf=ifsubdir.len==0:pkgelse:subdirletres=addFileExt(best/f,"nim")ifbest.len>0andfileExists(res):result=reswhenfalse:procresolveDollar(project,source,pkg,subdir:string;info:TLineInfo):string=templateattempt(a)=letx=addFileExt(a,"nim")iffileExists(x):returnxcasepkgof"stdlib":ifsubdir.len==0:returnoptions.libpathelse:forcandidateinstdlibDirs:attempt(options.libpath/candidate/subdir)of"root":letroot=project.splitFile.dirifsubdir.len==0:returnrootelse:attempt(root/subdir)else:whenconsiderParentDirs:varp=parentDir(source.splitFile.dir)# support 'import $karax':letf=ifsubdir.len==0:pkgelse:subdirwhilep.len>0:letdir=p/pkgifdirExists(dir):attempt(dir/f)# 2nd attempt: try to use 'karax/karax'attempt(dir/pkg/f)# 3rd attempt: try to use 'karax/src/karax'attempt(dir/"src"/f)attempt(dir/"src"/pkg/f)p=parentDir(p)whenconsiderNimbleDirs:ifnotoptions.gNoNimblePath:varnimbleDir=getEnv("NIMBLE_DIR")ifnimbleDir.len==0:nimbleDir=getHomeDir()/".nimble"result=findInNimbleDir(pkg,subdir,nimbleDir/"pkgs")ifresult.len>0:returnresultwhennotdefined(windows):result=findInNimbleDir(pkg,subdir,"/opt/nimble/pkgs")ifresult.len>0:returnresultprocscriptableImport(pkg,sub:string;info:TLineInfo):string=result=resolveDollar(gProjectFull,info.toFullPath(),pkg,sub,info)ifresult.isNil:result=""proclookupPackage(pkg,subdir:PNode):string=letsub=ifsubdir!=nil:renderTree(subdir,{renderNoComments}).replace(" ")else:""casepkg.kindofnkStrLit,nkRStrLit,nkTripleStrLit:result=scriptableImport(pkg.strVal,sub,pkg.info)ofnkIdent:result=scriptableImport(pkg.ident.s,sub,pkg.info)else:localError(pkg.info,"package name must be an identifier or string literal")result=""procgetModuleName*(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 validcasen.kindofnkStrLit,nkRStrLit,nkTripleStrLit:try:result=pathSubs(conf,n.strVal,toFullPath(conf,n.info).splitFile().dir).replace(" ")exceptValueError:localError(conf,n.info,"invalid path: "&n.strVal)result=n.strValofnkIdent:result=n.ident.sofnkSym:result=n.sym.name.sofnkInfix:letn0=n[0]letn1=n[1]whenfalse:ifn1.kind==nkPrefixandn1[0].kind==nkIdentandn1[0].ident.s=="$":ifn0.kind==nkIdentandn0.ident.s=="/":result=lookupPackage(n1[1],n[2])else:localError(n.info,"only '/' supported with $package notation")result=""else:letmodname=getModuleName(conf,n[2])# hacky way to implement 'x / y /../ z':result=getModuleName(conf,n1)result.addrenderTree(n0,{renderNoComments}).replace(" ")result.addmodnameofnkPrefix:whenfalse:ifn.sons[0].kind==nkIdentandn.sons[0].ident.s=="$":result=lookupPackage(n[1],nil)else:discard# hacky way to implement 'x / y /../ z':result=renderTree(n,{renderNoComments}).replace(" ")ofnkDotExpr:localError(conf,n.info,warnDeprecated,"using '.' instead of '/' in import paths")result=renderTree(n,{renderNoComments}).replace(".","/")ofnkImportAs:result=getModuleName(conf,n.sons[0])else:localError(conf,n.info,"invalid module name: '$1'"%n.renderTree)result=""proccheckModuleName*(conf:ConfigRef;n:PNode;doLocalError=true):FileIndex=# This returns the full canonical path for a given module importletmodulename=getModuleName(conf,n)letfullPath=findModule(conf,modulename,toFullPath(conf,n.info))iffullPath.isEmpty:ifdoLocalError:letm=ifmodulename.len>0:modulenameelse:$nlocalError(conf,n.info,"cannot open file: "&m)result=InvalidFileIDXelse:result=fileInfoIdx(conf,fullPath)