@@ -31,6 +31,250 @@ import util::Reflective;
3131import lang ::rascalcore ::compile ::util ::Names ; // TODO: refactor, this is an undesired dependency on compile
3232import lang ::rascalcore ::compile ::CompileTimeError ;
3333
34+
35+ str makeFileName (str qualifiedModuleName , str extension = "rsc" ) {
36+ str qnameSlashes = replaceAll (qualifiedModuleName , "::" , "/" );
37+ int n = findLast (qnameSlashes , "/" );
38+ str prefix = extension == "rsc" ? "" : "$" ;
39+ str package = extension == "rsc" ? "" : "rascal/" ;
40+ qnameSlashes = n < 0 ? "<prefix > " + qnameSlashes : qnameSlashes [0 ..n ] + "/<prefix > " + qnameSlashes [n +1 ..];
41+ return "<package ><qnameSlashes ><isEmpty (extension ) ? "" : ".<extension > " > " ;
42+ }
43+
44+ loc getSearchPathLoc (str filePath , PathConfig pcfg ){
45+ for (loc dir <- pcfg .srcs + pcfg .libs ){
46+ fileLoc = dir + filePath ;
47+ if (exists (fileLoc )){
48+ //println("getModuleLocation <qualifiedModuleName> =\> <fileLoc>");
49+ return fileLoc ;
50+ }
51+ }
52+ throw "Module with path <filePath > not found" ;
53+ }
54+
55+ @synopsis {Get the location of a named module, search for `src` in srcs and `tpl` in libs}
56+ loc getModuleLocation (str qualifiedModuleName , PathConfig pcfg ){
57+ fileName = makeFileName (qualifiedModuleName , extension ="rsc" );
58+ for (loc dir <- pcfg .srcs ){
59+ fileLoc = dir + fileName ;
60+ if (exists (fileLoc )){
61+ return fileLoc ;
62+ }
63+ }
64+ fileName = makeFileName (qualifiedModuleName , extension ="tpl" );
65+ for (loc dir <- pcfg .libs ){
66+ fileLoc = dir + fileName ;
67+
68+ if (exists (fileLoc )){
69+ return fileLoc ;
70+ }
71+ }
72+ throw "Module `<qualifiedModuleName > ` not found;\n <pcfg > " ;
73+ }
74+
75+ tuple [str ,str ] splitFileExtension (str path ){
76+ int n = findLast (path , "." );
77+ if (n < 0 ) return <path , "" > ;
78+ return <path [0 .. n ], path [n +1 .. ]> ;
79+ }
80+
81+ @synopsis {Determine length of common suffix of list of strings}
82+ int commonSuffix (list [str ] dir , list [str ] m )
83+ = commonPrefix (reverse (dir ), reverse (m ));
84+
85+ @synopsis {Determine length of common prefix of list of strings}
86+ int commonPrefix (list [str ] rdir , list [str ] rm ){
87+ for (int i <- index (rm )){
88+ if (i > = size (rdir )){
89+ return i ;
90+ } else if (rdir [i ] != rm [i ]){
91+ return i ;
92+ } else {
93+ continue ;
94+ }
95+ }
96+ return size (rm );
97+ }
98+
99+ @synopsis {Find the module name corresponding to a given module location via its (src or tpl) location}
100+ str getModuleName (loc moduleLoc , PathConfig pcfg ){
101+ modulePath = moduleLoc .path ;
102+
103+ rscFile = endsWith (modulePath , "rsc" );
104+ tplFile = endsWith (modulePath , "tpl" );
105+
106+ if (!( rscFile || tplFile )){
107+ throw "Not a Rascal .src or .tpl file: <moduleLoc > " ;
108+ }
109+
110+ if (contains (modulePath , "Content" )){
111+ println ("Content" );
112+ }
113+
114+ // Find matching .rsc file in source directories
115+ if (rscFile ){
116+ for (loc dir <- pcfg .srcs ){
117+ if (moduleLoc .authority == dir .authority && startsWith (modulePath , dir .path )) {
118+ moduleName = replaceFirst (modulePath , dir .path , "" );
119+ <moduleName , ext > = splitFileExtension (moduleName );
120+ if (moduleName [0 ] == "/" ){
121+ moduleName = moduleName [1 ..];
122+ }
123+ moduleName = replaceAll (moduleName , "/" , "::" );
124+ return moduleName ;
125+ }
126+ }
127+ }
128+
129+ // Find longest matching .tpl file in library directories
130+
131+ <modulePathNoExt , ext > = splitFileExtension (modulePath );
132+ while (modulePathNoExt [0 ] == "/" ){
133+ modulePathNoExt = modulePathNoExt [1 ..];
134+ }
135+
136+ modulePathAsList = split ("/" , modulePathNoExt );
137+ if (tplFile ){
138+ lastName = modulePathAsList [-1 ];
139+ if (lastName [0 ] == "$" ){
140+ modulePathAsList = [*modulePathAsList [..-1 ],lastName [1 ..]];
141+ }
142+ }
143+ if (modulePathAsList [0 ] == "rascal" ){
144+ modulePathAsList = modulePathAsList [1 ..];
145+ }
146+ modulePathReversed = reverse (modulePathAsList );
147+
148+ int longestSuffix = 0 ;
149+ for (loc dir <- pcfg .libs ){
150+ dir = dir + "rascal" ;
151+ dpath = dir .path ;
152+
153+ while (dpath [0 ] == "/" ){
154+ dpath = dpath [1 ..];
155+ }
156+
157+ for (loc file <- find (dir , "tpl" )){
158+ candidate = replaceFirst (file .path , dpath , "" );
159+ <candidate , ext > = splitFileExtension (candidate );
160+
161+ if (contains (candidate , "Content" )){
162+ println ("Content" );
163+ }
164+ while (candidate [0 ] == "/" ){
165+ candidate = candidate [1 ..];
166+ }
167+
168+ candidateAsList = split ("/" , candidate );
169+ lastName = candidateAsList [-1 ];
170+ if (lastName [0 ] == "$" ){
171+ candidateAsList = [*candidateAsList [..-1 ],lastName [1 ..]];
172+ }
173+ // println("cand: <candidateAsList>, modpath: <modulePathAsList>");
174+ n = commonPrefix (reverse (candidateAsList ), modulePathReversed );
175+
176+ if (n > longestSuffix ){
177+ longestSuffix = n ;
178+ }
179+ }
180+ }
181+
182+ if (longestSuffix > 0 ){
183+ lastName = modulePathAsList [-1 ];
184+ if (lastName [0 ] == "$" ){
185+ modulePathAsList = [*modulePathAsList [..-1 ],lastName [1 ..]];
186+ }
187+ return intercalate ("::" , modulePathAsList [size (modulePathAsList ) - longestSuffix .. ]);
188+ }
189+ throw "No module name found for <moduleLoc > ;\n srcs=<pcfg .srcs > ;\n libs=<pcfg .libs > " ;
190+ }
191+
192+ @synopsis {Derive a location from a given module name for reading}
193+ @description {
194+ Given a module name, a file name extension, and a PathConfig,
195+ a path name is constructed from the module name + extension.
196+
197+ If a file F with this path exists in one of the directories in the PathConfig,
198+ then the pair <true, F> is returned. Otherwise <false, some error location> is returned.
199+
200+ For a source extension (typically "rsc" or "mu" but this can be configured) srcs is searched, otherwise binPath + libs.
201+ }
202+ @examples {
203+ ```rascal-shell
204+ import util::Reflective;
205+ getDerivedReadLoc("List", "rsc", pathConfig());
206+ getDerivedReadLoc("experiments::Compiler::Compile", "rvm", pathConfig());
207+ getDerivedReadLoc("experiments::Compiler::muRascal2RVM::Library", "mu", pathConfig());
208+ ```
209+ }
210+ @benefits {
211+ This function is useful for type checking and compilation tasks, when derived information related to source modules has to be read
212+ from locations in different, configurable, directories.
213+ }
214+
215+ tuple [bool , loc ] getDerivedReadLoc (str qualifiedModuleName , str extension , PathConfig pcfg , set [str ] srcExtensions = {"rsc" , "mu" }, str rootDir = "" ){
216+ fileName = makeFileName (qualifiedModuleName , extension =extension );
217+ //println("getDerivedReadLoc: <fileName>");
218+
219+ if (extension in srcExtensions ){
220+ for (loc dir <- pcfg .srcs ){ // In a source directory?
221+ fileLoc = dir + rootDir + fileName ;
222+ if (exists (fileLoc )){
223+ //println("getDerivedReadLoc: <qualifiedModuleName>, <extension> =\> <fileLoc");
224+ return <true , fileLoc > ;
225+ }
226+ }
227+ } else {
228+ for (loc dir <- pcfg .bin + pcfg .libs ){ // In a bin or lib directory?
229+
230+ fileLoc = dir + rootDir + fileName ;
231+ if (exists (fileLoc )){
232+ //println("getDerivedReadLoc: <qualifiedModuleName>, <extension> =\> <fileLoc>");
233+ return <true , fileLoc > ;
234+ }
235+ }
236+ }
237+ //println("getDerivedReadLoc: <qualifiedModuleName>, <extension> =\> |error:///|");
238+ return <false , |error:///| > ;
239+ }
240+
241+
242+ @synopsis {Derive a location from a given module name for writing}
243+ @description {
244+ Given a module name, a file name extension, and a PathConfig,
245+ a path name is constructed from the module name + extension.
246+
247+ For source modules, a writable location cannot be derived.
248+ For other modules, a location for this path in bin will be returned.
249+ }
250+ @examples {
251+ ```rascal-shell
252+ import util::Reflective;
253+ getDerivedWriteLoc("List", "rvm", pathConfig());
254+ getDerivedWriteLoc("experiments::Compiler::Compile", "rvm", pathConfig());
255+ ```
256+
257+ ```rascal-shell,error
258+ getDerivedWriteLoc("experiments::Compiler::muRascal2RVM::Library", "rsc", pathConfig());
259+ ```
260+ }
261+ @benefits {
262+ This function is useful for type checking and compilation tasks, when derived information related to source modules has to be written
263+ to locations in separate, configurable, directories.
264+ }
265+ loc getDerivedWriteLoc (str qualifiedModuleName , str extension , PathConfig pcfg , set [str ] srcExtensions = {"rsc" , "mu" }, str rootDir = "" ){
266+ if (extension in srcExtensions ){
267+ throw "Cannot derive writable location for module <qualifiedModuleName > with extension <extension > " ;
268+ }
269+ fileNameSrc = makeFileName (qualifiedModuleName );
270+ fileNameBin = makeFileName (qualifiedModuleName , extension =extension );
271+
272+ bin = pcfg .bin ;
273+ fileLocBin = bin + rootDir + fileNameBin ;
274+ //println("getDerivedWriteLoc: <qualifiedModuleName>, <extension> =\> <fileLocBin>");
275+ return fileLocBin ;
276+ }
277+
34278void checkSupportedByParserGenerator (Tree t , Collector c ){
35279 c .require ("implemented by parsergenerator" , t , [t ], void (Solver s ){
36280 tp = s .getType (t );
0 commit comments