From 2a0b66d0e719c2c749d00d8d99f2601c0e4e6cb6 Mon Sep 17 00:00:00 2001 From: paulklint Date: Wed, 11 Dec 2024 21:15:08 +0100 Subject: [PATCH] Moved getModuleName and friends from util::Reflective to CheckerCommon --- .../lang/rascalcore/check/CheckerCommon.rsc | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/check/CheckerCommon.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/check/CheckerCommon.rsc index 787b4ace..ff9aa21c 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/check/CheckerCommon.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/check/CheckerCommon.rsc @@ -31,6 +31,250 @@ import util::Reflective; import lang::rascalcore::compile::util::Names; // TODO: refactor, this is an undesired dependency on compile import lang::rascalcore::compile::CompileTimeError; + +str makeFileName(str qualifiedModuleName, str extension = "rsc") { + str qnameSlashes = replaceAll(qualifiedModuleName, "::", "/"); + int n = findLast(qnameSlashes, "/"); + str prefix = extension == "rsc" ? "" : "$"; + str package = extension == "rsc" ? "" : "rascal/"; + qnameSlashes = n < 0 ? "" + qnameSlashes : qnameSlashes[0..n] + "/" + qnameSlashes[n+1..]; + return "">"; +} + +loc getSearchPathLoc(str filePath, PathConfig pcfg){ + for(loc dir <- pcfg.srcs + pcfg.libs){ + fileLoc = dir + filePath; + if(exists(fileLoc)){ + //println("getModuleLocation =\> "); + return fileLoc; + } + } + throw "Module with path not found"; +} + +@synopsis{Get the location of a named module, search for `src` in srcs and `tpl` in libs} +loc getModuleLocation(str qualifiedModuleName, PathConfig pcfg){ + fileName = makeFileName(qualifiedModuleName, extension="rsc"); + for(loc dir <- pcfg.srcs){ + fileLoc = dir + fileName; + if(exists(fileLoc)){ + return fileLoc; + } + } + fileName = makeFileName(qualifiedModuleName, extension="tpl"); + for(loc dir <- pcfg.libs){ + fileLoc = dir + fileName; + + if(exists(fileLoc)){ + return fileLoc; + } + } + throw "Module `` not found;\n"; +} + +tuple[str,str] splitFileExtension(str path){ + int n = findLast(path, "."); + if(n < 0) return ; + return ; +} + +@synopsis{Determine length of common suffix of list of strings} +int commonSuffix(list[str] dir, list[str] m) + = commonPrefix(reverse(dir), reverse(m)); + +@synopsis{Determine length of common prefix of list of strings} +int commonPrefix(list[str] rdir, list[str] rm){ + for(int i <- index(rm)){ + if(i >= size(rdir)){ + return i; + } else if(rdir[i] != rm[i]){ + return i; + } else { + continue; + } + } + return size(rm); +} + +@synopsis{Find the module name corresponding to a given module location via its (src or tpl) location} +str getModuleName(loc moduleLoc, PathConfig pcfg){ + modulePath = moduleLoc.path; + + rscFile = endsWith(modulePath, "rsc"); + tplFile = endsWith(modulePath, "tpl"); + + if(!( rscFile || tplFile )){ + throw "Not a Rascal .src or .tpl file: "; + } + + if(contains(modulePath, "Content")){ + println("Content"); + } + + // Find matching .rsc file in source directories + if(rscFile){ + for(loc dir <- pcfg.srcs){ + if(moduleLoc.authority == dir.authority && startsWith(modulePath, dir.path)) { + moduleName = replaceFirst(modulePath, dir.path, ""); + = splitFileExtension(moduleName); + if(moduleName[0] == "/"){ + moduleName = moduleName[1..]; + } + moduleName = replaceAll(moduleName, "/", "::"); + return moduleName; + } + } + } + + // Find longest matching .tpl file in library directories + + = splitFileExtension(modulePath); + while(modulePathNoExt[0] == "/"){ + modulePathNoExt = modulePathNoExt[1..]; + } + + modulePathAsList = split("/", modulePathNoExt); + if(tplFile){ + lastName = modulePathAsList[-1]; + if(lastName[0] == "$"){ + modulePathAsList = [*modulePathAsList[..-1],lastName[1..]]; + } + } + if(modulePathAsList[0] == "rascal"){ + modulePathAsList = modulePathAsList[1..]; + } + modulePathReversed = reverse(modulePathAsList); + + int longestSuffix = 0; + for(loc dir <- pcfg.libs){ + dir = dir + "rascal"; + dpath = dir.path; + + while(dpath[0] == "/"){ + dpath = dpath[1..]; + } + + for(loc file <- find(dir, "tpl")){ + candidate = replaceFirst(file.path, dpath, ""); + = splitFileExtension(candidate); + + if(contains(candidate, "Content")){ + println("Content"); + } + while(candidate[0] == "/"){ + candidate = candidate[1..]; + } + + candidateAsList = split("/", candidate); + lastName = candidateAsList[-1]; + if(lastName[0] == "$"){ + candidateAsList = [*candidateAsList[..-1],lastName[1..]]; + } + // println("cand: , modpath: "); + n = commonPrefix(reverse(candidateAsList), modulePathReversed); + + if(n > longestSuffix){ + longestSuffix = n; + } + } + } + + if(longestSuffix > 0){ + lastName = modulePathAsList[-1]; + if(lastName[0] == "$"){ + modulePathAsList = [*modulePathAsList[..-1],lastName[1..]]; + } + return intercalate("::", modulePathAsList[size(modulePathAsList) - longestSuffix .. ]); + } + throw "No module name found for ;\nsrcs=;\nlibs="; +} + +@synopsis{Derive a location from a given module name for reading} +@description{ +Given a module name, a file name extension, and a PathConfig, +a path name is constructed from the module name + extension. + +If a file F with this path exists in one of the directories in the PathConfig, +then the pair is returned. Otherwise is returned. + +For a source extension (typically "rsc" or "mu" but this can be configured) srcs is searched, otherwise binPath + libs. +} +@examples{ +```rascal-shell +import util::Reflective; +getDerivedReadLoc("List", "rsc", pathConfig()); +getDerivedReadLoc("experiments::Compiler::Compile", "rvm", pathConfig()); +getDerivedReadLoc("experiments::Compiler::muRascal2RVM::Library", "mu", pathConfig()); +``` +} +@benefits{ +This function is useful for type checking and compilation tasks, when derived information related to source modules has to be read +from locations in different, configurable, directories. +} + +tuple[bool, loc] getDerivedReadLoc(str qualifiedModuleName, str extension, PathConfig pcfg, set[str] srcExtensions = {"rsc", "mu"}, str rootDir = ""){ + fileName = makeFileName(qualifiedModuleName, extension=extension); + //println("getDerivedReadLoc: "); + + if(extension in srcExtensions){ + for(loc dir <- pcfg.srcs){ // In a source directory? + fileLoc = dir + rootDir + fileName; + if(exists(fileLoc)){ + //println("getDerivedReadLoc: , =\> ; + } + } + } else { + for(loc dir <- pcfg.bin + pcfg.libs){ // In a bin or lib directory? + + fileLoc = dir + rootDir + fileName; + if(exists(fileLoc)){ + //println("getDerivedReadLoc: , =\> "); + return ; + } + } + } + //println("getDerivedReadLoc: , =\> |error:///|"); + return ; +} + + +@synopsis{Derive a location from a given module name for writing} +@description{ +Given a module name, a file name extension, and a PathConfig, +a path name is constructed from the module name + extension. + +For source modules, a writable location cannot be derived. +For other modules, a location for this path in bin will be returned. +} +@examples{ +```rascal-shell +import util::Reflective; +getDerivedWriteLoc("List", "rvm", pathConfig()); +getDerivedWriteLoc("experiments::Compiler::Compile", "rvm", pathConfig()); +``` + +```rascal-shell,error +getDerivedWriteLoc("experiments::Compiler::muRascal2RVM::Library", "rsc", pathConfig()); +``` +} +@benefits{ +This function is useful for type checking and compilation tasks, when derived information related to source modules has to be written +to locations in separate, configurable, directories. +} +loc getDerivedWriteLoc(str qualifiedModuleName, str extension, PathConfig pcfg, set[str] srcExtensions = {"rsc", "mu"}, str rootDir = ""){ + if(extension in srcExtensions){ + throw "Cannot derive writable location for module with extension "; + } + fileNameSrc = makeFileName(qualifiedModuleName); + fileNameBin = makeFileName(qualifiedModuleName, extension=extension); + + bin = pcfg.bin; + fileLocBin = bin + rootDir + fileNameBin; + //println("getDerivedWriteLoc: , =\> "); + return fileLocBin; +} + void checkSupportedByParserGenerator(Tree t, Collector c){ c.require("implemented by parsergenerator", t, [t], void(Solver s){ tp = s.getType(t);