Source code: org/sablecc/sablecc/Inlining.java
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * This file is part of SableCC. *
3 * See the file "LICENSE" for copyright information and the *
4 * terms and conditions for copying, distribution and *
5 * modification of SableCC. *
6 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7
8 package org.sablecc.sablecc;
9
10 import java.util.*;
11 import org.sablecc.sablecc.analysis.*;
12 import org.sablecc.sablecc.node.*;
13
14 public class Inlining
15 {
16 public static LinkedList productionsToBeRemoved =
17 new TypedLinkedList(StringCast.instance);
18
19 private AProd current_production;
20
21 //The production to inline within current_production
22 private In_Production prod_to_inline;
23
24 public Inlining(AProd curr_prod, In_Production prod_to_inline)
25 {
26 this.current_production = curr_prod;
27 this.prod_to_inline = prod_to_inline;
28 }
29
30 /*
31 * The core of inlining is done here.
32 * returns true if it succeed and false otherwise
33 */
34 public boolean inlineProduction()
35 {
36 AParsedAlt[] alts = (AParsedAlt[])current_production.getAlts().toArray(new AParsedAlt[0]);
37 final BooleanEx prodMustBeInlined = new BooleanEx(false);
38
39 /*
40 We're trying to detect if the current production must be inlined.
41 ie one of its alternatives contains production to inline
42 */
43 for(int i=0; i<alts.length; i++)
44 {
45 ((PAlt)alts[i]).apply( new DepthFirstAdapter()
46 {
47 public void caseAElem(AElem node)
48 {
49 String elem_name = node.getId().getText();
50
51 if(elem_name.equals(prod_to_inline.getName()) &&
52 !(node.getSpecifier() instanceof ATokenSpecifier) )
53 {
54 prodMustBeInlined.setValue(true);
55 }
56 }
57 }
58 );
59 //We only need to know if one element within one of the production alternatives matches.
60 if(prodMustBeInlined.getValue())
61 {
62 break;
63 }
64 }
65
66 if(prodMustBeInlined.getValue())
67 {
68 //list of productions which inlining was a success.
69 if( !productionsToBeRemoved.contains(ResolveIds.name(prod_to_inline.getName())) )
70 {
71 productionsToBeRemoved.add("P" + ResolveIds.name(prod_to_inline.getName()));
72 }
73
74 /*
75 Once we detect that the production can be inline,
76 we try to inline each of its alternatives.
77 */
78 LinkedList listOfAlts = new TypedLinkedList(NodeCast.instance);
79 for(int i=0; i<alts.length; i++)
80 {
81 listOfAlts.addAll( inlineAlternative(alts[i]) );
82 }
83 current_production.setAlts(listOfAlts);
84 return true;
85 }
86 return false;
87 }
88
89 /*
90 * Inlining of an alternative
91 *
92 */
93 public LinkedList inlineAlternative(AParsedAlt alt)
94 {
95 AElem[] elems = (AElem[])alt.getElems().toArray(new AElem[0]);
96 String elem_name ;
97 LinkedList eventualProdIdOrNames = new LinkedList();
98 int occurenceNb = 0;
99
100 for(int i=0; i<elems.length; i++)
101 {
102 elem_name = elems[i].getId().getText();
103
104 /*
105 Element to inline within an alternative is added to
106 a list of occurrences of the production to inline
107 */
108 if(elem_name.equals(prod_to_inline.getName()) &&
109 !(elems[i].getSpecifier() instanceof ATokenSpecifier) )
110 {
111 occurenceNb++;
112 if(elems[i].getElemName() != null)
113 {
114 eventualProdIdOrNames.add( elems[i].getElemName().getText() );
115 }
116 else
117 {
118 eventualProdIdOrNames.add( elems[i].getId().getText() );
119 }
120 }
121 }
122 alt.apply(new PrettyPrinter());
123
124 LinkedList resultingListOfAlts = new TypedLinkedList();
125 resultingListOfAlts.add(alt);
126 for(int i=0; i<occurenceNb; i++)
127 {
128 resultingListOfAlts = inline(resultingListOfAlts, i+1);
129 }
130
131 return resultingListOfAlts;
132 }
133
134 String alt_elem_info = null;
135 /*
136 * whichOccurence is used to number element within the alternative
137 */
138 public LinkedList inline(LinkedList altsList, int whichOccurence)
139 {
140 LinkedList resultList = new LinkedList();
141 AParsedAlt[] alts = (AParsedAlt[])altsList.toArray(new AParsedAlt[0]);
142 AParsedAlt aParsed_alt;
143 Map mapOfNewTermNames;
144
145 for(int i=0; i<alts.length; i++)
146 {
147 aParsed_alt = alts[i];
148
149 for(int j=0; j<prod_to_inline.getNbAlts(); j++)
150 {
151 mapOfNewTermNames = new TypedHashMap(StringCast.instance,
152 StringCast.instance);
153
154 LinkedList listElems = inlineList(aParsed_alt.getElems(),
155 prod_to_inline.getAlternative(j).getElems(),
156 mapOfNewTermNames);
157 AAltTransform aAltTransform =
158 (AAltTransform)((AAltTransform)aParsed_alt.getAltTransform()).clone();
159 final Map currentMap = prod_to_inline.getAlternative(j).getProdTransform_AlTransformMap();
160
161 aAltTransform.apply(new DepthFirstAdapter()
162 {
163 public void caseASimpleTerm(ASimpleTerm node)
164 {
165 if(node.getId().getText().equals(alt_elem_info) &&
166 !(node.getSpecifier() instanceof ATokenSpecifier) )
167 {
168 String termTail;
169 if(node.getSimpleTermTail() != null)
170 {
171 termTail = node.getSimpleTermTail().getText();
172 }
173 else
174 {
175 termTail = prod_to_inline.getName();
176 }
177
178 PTerm term = (PTerm)((PTerm)currentMap.get(termTail)).clone();
179
180 if(currentMap.get(termTail) != null)
181 {
182 node.replaceBy(term);
183 }
184 }
185 }
186
187 public void caseASimpleListTerm(final ASimpleListTerm node_)
188 {
189 if(node_.getId().getText().equals(alt_elem_info) &&
190 !(node_.getSpecifier() instanceof ATokenSpecifier) )
191 {
192 String termTail;
193 if(node_.getSimpleTermTail() != null)
194 {
195 termTail = node_.getSimpleTermTail().getText();
196 }
197 else
198 {
199 termTail = prod_to_inline.getName();
200 }
201
202 if(currentMap.get(termTail) != null)
203 {
204 PTerm term = (PTerm)currentMap.get(termTail);
205
206 if( !(currentMap.get(termTail) instanceof ANewListTerm) &&
207 !(currentMap.get(termTail) instanceof ASimpleListTerm)
208 )
209 {
210 term.apply(new DepthFirstAdapter()
211 {
212 public void caseANewTerm(ANewTerm node)
213 {
214 node_.replaceBy( new ANewListTerm( (AProdName)node.getProdName().clone(),
215 (TLPar)node.getLPar().clone(),
216 (LinkedList)cloneList(node.getParams())
217 )
218 );
219 }
220
221 public void caseASimpleTerm(ASimpleTerm node)
222 {
223 PSpecifier specifier = null;
224 TId simpleTermTail = null;
225 if(node.getSpecifier() != null)
226 {
227 specifier = (PSpecifier)node.getSpecifier().clone();
228 }
229 if(node.getSimpleTermTail() != null)
230 {
231 simpleTermTail = (TId)node.getSimpleTermTail().clone();
232 }
233 node_.replaceBy( new ASimpleListTerm( specifier,
234 (TId)node.getId().clone(),
235 simpleTermTail
236 )
237 );
238 }
239
240 public void caseNullTerm(ANullTerm node)
241 {
242 node_.replaceBy( null );
243 }
244
245 public void caseAListTerm(AListTerm node)
246 {
247 AListTerm parent = (AListTerm)node_.parent();
248 LinkedList oldlistTerms = parent.getListTerms();
249 LinkedList newlistTerms = new LinkedList();
250
251 Object[] oldListTermsArray = (Object[]) oldlistTerms.toArray();
252 for(int i=0; i<oldListTermsArray.length; i++)
253 {
254 if(oldListTermsArray[i] != node_)
255 {
256 if(oldListTermsArray[i] instanceof PTerm)
257 {
258 newlistTerms.add( ((PTerm)oldListTermsArray[i]).clone() );
259 }
260 else
261 {
262 newlistTerms.add( ((PListTerm)oldListTermsArray[i]).clone() );
263 }
264 }
265 else
266 {
267 newlistTerms.addAll(cloneList(node.getListTerms()));
268 }
269 }
270 parent.setListTerms(newlistTerms);
271 }
272 }
273 );
274 }
275 else
276 {
277 node_.replaceBy(term);
278 }
279 }
280 }
281 }
282 }
283 );
284
285 AAltTransform tmpaAltTransform = (AAltTransform)aAltTransform.clone();
286 fixSimpleTermOrSimpleListTermNames(tmpaAltTransform, mapOfNewTermNames);
287 String newAltName;
288 if(aParsed_alt.getAltName() != null)
289 {
290 newAltName = aParsed_alt.getAltName().getText()+ "$" +
291 prod_to_inline.getAlternative(j).getName() + whichOccurence;
292 }
293 else
294 {
295 newAltName = prod_to_inline.getAlternative(j).getName() + whichOccurence;
296 }
297
298 resultList.add( new AParsedAlt(new TId(newAltName),
299 listElems,
300 //(AAltTransform)aAltTransform.clone()
301 tmpaAltTransform)
302 );
303 }
304 }
305 return resultList;
306 }
307
308 public LinkedList inlineList(LinkedList oldElemsList,
309 AElem[] inliningProductionsElems,
310 Map mapOfNewTermNames)
311 {
312 int position = 0;
313 AElem[] listElems = (AElem[]) oldElemsList.toArray(new AElem[0]);
314 for(int i=0; i<listElems.length; i++)
315 {
316 if( listElems[i].getId().getText().equals(prod_to_inline.getName()) )
317 {
318 /*if( (listElems[i].getElemName() != null && listElems[i].getElemName().getText().equals(name) )
319 || listElems[i].getElemName() == null )
320 {*/
321 position = i;
322 if(listElems[i].getElemName() != null)
323 {
324 alt_elem_info = listElems[i].getElemName().getText();
325 }
326 else
327 {
328 alt_elem_info = listElems[i].getId().getText();
329 }
330 break;
331 //}
332 }
333 }
334
335 LinkedList list = new LinkedList();
336 int elemPosition = 1;
337 for(int i=0; i<position; i++)
338 {
339 list.add(((AElem)oldElemsList.get(i)).clone() );
340 }
341
342 for(int i=0; i<inliningProductionsElems.length; i++)
343 {
344 list.add(inliningProductionsElems[i].clone());
345 }
346
347 for(int i=position+1; i<listElems.length; i++)
348 {
349 list.add(((AElem)oldElemsList.get(i)).clone());
350 }
351
352 AElem[] listOfAltElems = (AElem[]) list.toArray(new AElem[0]);
353 for(int i=0; i<listOfAltElems.length; i++)
354 {
355 String old_name = listOfAltElems[i].getId().getText();
356 TId elemName = (TId)listOfAltElems[i].getElemName();
357 if(elemName != null)
358 {
359 elemName = (TId)elemName;
360 old_name = elemName.getText();
361 }
362
363 String elemNameString = (elemName != null ? elemName.getText() : "elem" );
364 elemNameString += (i+1);
365 listOfAltElems[i].setElemName(new TId(elemNameString));
366 mapOfNewTermNames.put(old_name, elemNameString);
367 }
368
369 return list;
370 }
371
372 private void fixSimpleTermOrSimpleListTermNames(AAltTransform tmpaAltTransform,
373 final Map mapOldNameNewNames)
374 {
375 tmpaAltTransform.apply(new DepthFirstAdapter()
376 {
377 public void caseASimpleTerm(ASimpleTerm node)
378 {
379 if(mapOldNameNewNames.get(node.getId().getText()) != null)
380 {
381 node.setId(new TId( (String)mapOldNameNewNames.get(node.getId().getText()) ));
382 }
383 }
384
385 public void caseASimpleListTerm(ASimpleListTerm node)
386 {
387 if(mapOldNameNewNames.get(node.getId().getText()) != null)
388 {
389 node.setId(new TId( (String)mapOldNameNewNames.get(node.getId().getText()) ));
390 }
391 }
392 }
393 );
394 }
395
396 private List cloneList(List list)
397 {
398 List clone = new LinkedList();
399
400 for(Iterator i = list.iterator(); i.hasNext();)
401 {
402 clone.add(((Node) i.next()).clone());
403 }
404
405 return clone;
406 }
407
408 class BooleanEx
409 {
410 boolean value;
411
412 BooleanEx(boolean value)
413 {
414 this.value = value;
415 }
416
417 void setValue(boolean value)
418 {
419 this.value = value;
420 }
421
422 boolean getValue()
423 {
424 return value;
425 }
426 }
427
428 }