Erosion and dilasion by square successfully tested.
[Faustine.git] / interpretor / faust-0.9.47mr3 / compiler / parser / sourcereader.cpp
1 /*
2 sourcereader : Faust source file reader
3
4 This component is in charge of mapping filenames to
5 the list of faust definitions they contain.
6
7 */
8 #include <iostream>
9 #include <map>
10 #include <list>
11 #include <string>
12
13
14 #include "sourcereader.hh"
15 #include "enrobage.hh"
16 #include "ppbox.hh"
17
18 using namespace std;
19
20 extern map<Tree, set<Tree> > gMetaDataSet;
21 extern string gMasterDocument;
22 extern vector<Tree> gDocVector;
23 extern bool gLatexDocSwitch;
24
25 /****************************************************************
26 Parser variables
27 *****************************************************************/
28
29
30 int yyparse();
31
32 extern int yyerr;
33 extern int yydebug;
34 extern FILE* yyin;
35 extern int yylineno;
36 extern const char * yyfilename;
37
38 extern Tree gResult;
39 extern Tree gResult2;
40
41
42
43
44 /**
45 * Checks an argument list for containing only
46 * standard identifiers, no patterns and
47 * is linear.
48 * @param args the argument list to check
49 * @return true if it contains only identifiers
50 */
51
52 static bool standardArgList(Tree args)
53 {
54 map<Tree,int> L;
55 while (isList(args)) {
56 if (!isBoxIdent(hd(args))) return false;
57 if (++L[hd(args)] > 1) return false;
58 args = tl(args);
59 }
60 return true;
61 }
62
63
64 static void printPatternError(Tree lhs1, Tree rhs1, Tree lhs2, Tree rhs2)
65 {
66 cerr << "ERROR : inconsistent number of parameters in pattern-matching rule: "
67 << boxpp(reverse(lhs2)) << " => " << boxpp(rhs2) << ";"
68 << " previous rule was: "
69 << boxpp(reverse(lhs1)) << " => " << boxpp(rhs1) << ";"
70 << endl;
71 }
72
73 Tree checkRulelist (Tree lr)
74 {
75 Tree lrules = lr;
76 if (isNil(lrules)) { cerr << "ERROR : a case expression can't be empty" << endl; exit(1); }
77 // first pattern used as a reference
78 Tree lhs1 = hd(hd(lrules));
79 Tree rhs1 = tl(hd(lrules));
80 int npat = len(lhs1);
81 lrules = tl(lrules);
82 while (! isNil(lrules)) {
83 Tree lhs2 = hd(hd(lrules));
84 Tree rhs2 = tl(hd(lrules));
85 if (npat != len(lhs2)) {
86 printPatternError(lhs1,rhs1,lhs2,rhs2);
87 exit(1);
88 }
89
90 lhs1 = lhs2;
91 rhs1 = rhs2;
92 lrules = tl(lrules);
93 }
94 return lr;
95 }
96
97
98 /**
99 * Transforms a list of variants (arglist.body)
100 * into an abstraction or a boxCase.
101 * @param variants list of variants (arglist.body)
102 * @return the corresponding box expression
103 */
104 static Tree makeDefinition(list<Tree>& variants)
105 {
106 if (variants.size() == 1) {
107 Tree rhs = *(variants.begin());
108 Tree args= hd(rhs);
109 Tree body= tl(rhs);
110
111 if (isNil(args)) {
112 return body;
113 } else if (standardArgList(args)) {
114 return buildBoxAbstr(args, body);
115 } else {
116 return boxCase(cons(rhs,nil));
117 }
118 } else {
119 list<Tree>::iterator p;
120 Tree l = nil;
121 Tree prev = *variants.begin();
122 int npat = len(hd(prev));
123 for (p=variants.begin(); p!=variants.end(); p++) {
124 Tree cur = *p;
125 if (npat != len(hd(cur))) {
126 printPatternError(hd(prev), tl(prev), hd(cur), tl(cur));
127 exit(1);
128 }
129 prev = cur;
130 l = cons(*p,l);
131 }
132 return boxCase(l);
133 }
134 }
135
136
137
138 /**
139 * Formats a list of raw definitions represented by triplets
140 * <name,arglist,body> into abstractions or pattern
141 * matching rules when appropriate.
142 *
143 * @param rldef list of raw definitions in reverse order
144 * @return the list of formatted definitions
145 */
146 Tree formatDefinitions(Tree rldef)
147 {
148 map<Tree,list<Tree> > dic;
149 map<Tree,list<Tree> >::iterator p;
150 Tree ldef2 = nil;
151 Tree file;
152
153 //cout << "Format definitions " << *rldef << endl;
154 // collects the definitions in a dictionnary
155 while (!isNil(rldef)) {
156 Tree def = hd(rldef);
157 rldef = tl(rldef);
158 if (isImportFile(def, file)) {
159 ldef2 = cons(def,ldef2);
160 } else if (!isNil(def)) {
161 //cout << " def : " << *def << endl;
162 dic[hd(def)].push_front(tl(def));
163 }
164 }
165
166 // produce the definitions
167
168 for (p=dic.begin(); p!=dic.end(); p++) {
169 ldef2 = cons (cons(p->first, makeDefinition(p->second)), ldef2);
170 }
171
172 //cout << "list of definitions : " << *ldef2 << endl;
173 return ldef2;
174
175 }
176
177
178 /**
179 * Parse a single faust source file. returns the list of
180 * definitions it contains.
181 *
182 * @param fname the name of the file to parse
183 * @return the list of definitions it contains
184 */
185
186 Tree SourceReader::parse(string fname)
187 {
188 string fullpath;
189
190 yyerr = 0;
191
192 yyfilename = fname.c_str();
193 yyin = fopensearch(yyfilename, fullpath);
194 if (yyin == NULL) {
195 fprintf(stderr, "ERROR : Unable to open file %s \n", yyfilename);
196 exit(1);
197 }
198
199 yylineno = 1;
200 int r = yyparse();
201 if (r) {
202 fprintf(stderr, "Parse error : code = %d \n", r);
203 }
204 if (yyerr > 0) {
205 //fprintf(stderr, "Erreur de parsing 2, count = %d \n", yyerr);
206 exit(1);
207 }
208
209 // we have parsed a valid file
210 fFilePathnames.push_back(fullpath);
211 return gResult;
212 }
213
214
215 /**
216 * Check if a file as been read and is in the "cache"
217 *
218 * @param fname the name of the file to check
219 * @return true if the file is in the cache
220 */
221
222 bool SourceReader::cached(string fname)
223 {
224 return fFileCache.find(fname) != fFileCache.end();
225 }
226
227
228 /**
229 * Return the list of definitions file contains. Cache the result.
230 *
231 * @param fname the name of the file to check
232 * @return the list of definitions it contains
233 */
234
235 Tree SourceReader::getlist(string fname)
236 {
237 if (!cached(fname)) {
238 fFileCache[fname] = parse(fname);
239 }
240 if (fFileCache[fname] == 0) exit(1);
241 return fFileCache[fname];
242 }
243
244
245 /**
246 * Return a vector of pathnames representing the list
247 * of all the source files that have been required
248 * to evaluate process (those in fFileCache)
249 */
250
251 vector<string> SourceReader::listSrcFiles()
252 {
253 // vector<string> srcfiles;
254
255 // for (map<string, Tree>::const_iterator p = fFileCache.begin(); p != fFileCache.end(); p++) {
256 // srcfiles.push_back(p->first);
257 // }
258
259 // return srcfiles;
260 return fFilePathnames;
261 }
262
263
264 /**
265 * Return the list of definitions where all imports have been expanded.
266 *
267 * @param ldef the list of definitions to expand
268 * @return the expanded list of definitions
269 */
270
271 Tree SourceReader::expandlist(Tree ldef)
272 {
273 set<string> visited;
274 return expandrec(ldef, visited, nil);
275 }
276
277 Tree SourceReader::expandrec(Tree ldef, set<string>& visited, Tree lresult)
278 {
279 for (;!isNil(ldef); ldef = tl(ldef)) {
280 Tree d = hd(ldef);
281 Tree fname;
282 if (isNil(d)) {
283 // skill null definitions produced by declarations
284 } else if (isImportFile(d,fname)) {
285 string f = tree2str(fname);
286 //cerr << "import(" << f << ")" << endl;
287
288 //string f = tree2str(fname);
289 if (visited.find(f) == visited.end()) {
290 visited.insert(f);
291 //Tree l = getlist(f);
292 lresult = expandrec(getlist(f), visited, lresult);
293 }
294
295 } else {
296 lresult = cons(d, lresult);
297 }
298 }
299 return lresult;
300 }
301
302
303 void declareMetadata(Tree key, Tree value)
304 {
305 if (gMasterDocument == yyfilename) {
306 // inside master document, no prefix needed to declare metadata
307 gMetaDataSet[key].insert(value);
308 } else {
309 string fkey(yyfilename);
310 fkey += "/";
311 fkey += tree2str(key);
312 gMetaDataSet[tree(fkey.c_str())].insert(value);
313 }
314 //cout << "Master " << gMasterDocument << ", file " << yyfilename << " : declare " << *key << "," << *value << endl;
315 }
316
317
318 void declareDoc(Tree t)
319 {
320 //gLatexDocSwitch = true;
321 gDocVector.push_back(t);
322 }