001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2004-2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.parser;
020:
021: import java.util.ArrayList;
022: import java.util.List;
023:
024: import xtc.tree.Attribute;
025: import xtc.tree.Comment;
026: import xtc.tree.Node;
027: import xtc.tree.Visitor;
028:
029: /**
030: * Visitor to copy grammar nodes. This visitor makes deep copies of
031: * grammars, modules, productions, and elements. Note that when
032: * copying elements, this visitor must be invoked through the {@link
033: * #copy(Element)} method. Further note that, if the element to be
034: * copied contains a generic node value or a generic recursion value,
035: * the element must also contain all bindings referenced by that value
036: * element. Otherwise, an <code>IllegalArgumentException</code> is
037: * signalled.
038: *
039: * @author Robert Grimm
040: * @version $Revision: 1.51 $
041: */
042: public class Copier extends Visitor {
043:
044: /** The list of source bindings. */
045: protected List<Binding> source;
046:
047: /** The list of target bindings. */
048: protected List<Binding> target;
049:
050: /** Create a new copier. */
051: public Copier() {
052: source = new ArrayList<Binding>();
053: target = new ArrayList<Binding>();
054: }
055:
056: /**
057: * Match the specified binding with its copy.
058: *
059: * @param b The binding.
060: * @return The corresponding copy.
061: * @throws IllegalArgumentException Signals that the specified
062: * binding has no copy.
063: */
064: protected Binding match(Binding b) {
065: final int size = source.size();
066:
067: int idx = -1;
068: for (int i = 0; i < size; i++) {
069: if (b == source.get(i)) {
070: idx = i;
071: break;
072: }
073: }
074:
075: if (-1 == idx) {
076: throw new IllegalArgumentException(
077: "Copying element without binding for " + b.name);
078: }
079:
080: return target.get(idx);
081: }
082:
083: /**
084: * Patch the specified bindings. This method replaces the source
085: * bindings in the specified list of bindings with the corresponding
086: * copies, thus ensuring that the list contains previously copied
087: * bindings.
088: *
089: * @param bindings The bindings to patch.
090: */
091: protected void patch(List<Binding> bindings) {
092: final int size = bindings.size();
093: for (int i = 0; i < size; i++) {
094: bindings.set(i, match(bindings.get(i)));
095: }
096: }
097:
098: /**
099: * Copy the specified element.
100: *
101: * @param e The element.
102: * @return A deep copy.
103: * @throws IllegalArgumentException
104: * Signals that the specified element is incomplete.
105: */
106: @SuppressWarnings("unchecked")
107: public <T extends Element> T copy(T e) {
108: // Clear the lists of bindings.
109: source.clear();
110: target.clear();
111:
112: return (T) dispatch(e);
113: }
114:
115: /** Copy the specified grammar. */
116: public Grammar visit(Grammar g) {
117: Grammar copy = new Grammar(new ArrayList<Module>(g.modules
118: .size()));
119: copy.setLocation(g);
120: for (Module m : g.modules) {
121: copy.modules.add((Module) dispatch(m));
122: }
123: return copy;
124: }
125:
126: /** Copy the specified module. */
127: public Module visit(Module m) {
128: Module copy = new Module();
129: copy.setLocation(m);
130: copy.documentation = (Comment) dispatch(m.documentation);
131: copy.name = m.name;
132: copy.parameters = (ModuleList) dispatch(m.parameters);
133: if (null != m.dependencies) {
134: copy.dependencies = new ArrayList<ModuleDependency>(
135: m.dependencies.size());
136: for (ModuleDependency dep : m.dependencies) {
137: copy.dependencies.add((ModuleDependency) dispatch(dep));
138: }
139: }
140: copy.modification = m.modification;
141: copy.header = (Action) dispatch(m.header);
142: copy.body = (Action) dispatch(m.body);
143: copy.footer = (Action) dispatch(m.footer);
144: if (null != m.attributes) {
145: copy.attributes = new ArrayList<Attribute>(m.attributes);
146: }
147: copy.productions = new ArrayList<Production>(m.productions
148: .size());
149: for (Production p : m.productions) {
150: copy.productions.add((Production) dispatch(p));
151: }
152: return copy;
153: }
154:
155: /** Copy the specified comment. */
156: public Comment visit(Comment c) {
157: Node node = (Node) dispatch(c.getNode());
158: Comment copy = new Comment(c.kind,
159: new ArrayList<String>(c.text), node);
160: copy.setLocation(c);
161:
162: return copy;
163: }
164:
165: /** Copy the specified module import declaration. */
166: public ModuleImport visit(ModuleImport i) {
167: ModuleImport copy = new ModuleImport(i.module,
168: (ModuleList) dispatch(i.arguments), i.target);
169: copy.setLocation(i);
170: return copy;
171: }
172:
173: /** Copy the specified module instantiation declaration. */
174: public ModuleInstantiation visit(ModuleInstantiation i) {
175: ModuleInstantiation copy = new ModuleInstantiation(i.module,
176: (ModuleList) dispatch(i.arguments), i.target);
177: copy.setLocation(i);
178: return copy;
179: }
180:
181: /** Copy the specified module modification. */
182: public ModuleModification visit(ModuleModification m) {
183: ModuleModification copy = new ModuleModification(m.module,
184: (ModuleList) dispatch(m.arguments), m.target);
185: copy.setLocation(m);
186: return copy;
187: }
188:
189: /** Copy the specified module list. */
190: public ModuleList visit(ModuleList l) {
191: ModuleList copy = new ModuleList(new ArrayList<ModuleName>(
192: l.names));
193: copy.setLocation(l);
194: return copy;
195: }
196:
197: /** Copy the specified full production. */
198: public FullProduction visit(FullProduction p) {
199: FullProduction copy = new FullProduction(null, p.type, p.name,
200: p.qName, copy(p.choice));
201: copy.setLocation(p);
202: if (null != p.attributes) {
203: copy.attributes = new ArrayList<Attribute>(p.attributes);
204: }
205: copy.dType = p.dType;
206: return copy;
207: }
208:
209: /** Copy the specified alternative addition. */
210: public AlternativeAddition visit(AlternativeAddition p) {
211: AlternativeAddition copy = new AlternativeAddition(p.dType,
212: p.name, copy(p.choice), p.sequence, p.isBefore);
213: copy.setLocation(p);
214: copy.type = p.type;
215: copy.qName = p.qName;
216: return copy;
217: }
218:
219: /** Copy the specified alternative removal. */
220: public AlternativeRemoval visit(AlternativeRemoval p) {
221: AlternativeRemoval copy = new AlternativeRemoval(p.dType,
222: p.name, new ArrayList<SequenceName>(p.sequences));
223: copy.setLocation(p);
224: copy.type = p.type;
225: copy.qName = p.qName;
226: return copy;
227: }
228:
229: /** Copy the specified production override. */
230: public ProductionOverride visit(ProductionOverride p) {
231: ProductionOverride copy = new ProductionOverride(p.dType,
232: p.name, copy(p.choice), p.isComplete);
233: copy.setLocation(p);
234: if (null != p.attributes) {
235: copy.attributes = new ArrayList<Attribute>(p.attributes);
236: }
237: copy.type = p.type;
238: copy.qName = p.qName;
239: return copy;
240: }
241:
242: /** Copy the specified ordered choice. */
243: public OrderedChoice visit(OrderedChoice c) {
244: final int length = c.alternatives.size();
245: OrderedChoice copy = new OrderedChoice(new ArrayList<Sequence>(
246: length));
247: copy.setLocation(c);
248: for (Sequence alt : c.alternatives) {
249: copy.alternatives.add((Sequence) dispatch(alt));
250: }
251: return copy;
252: }
253:
254: /** Copy the specified repetition. */
255: public Repetition visit(Repetition r) {
256: Repetition copy = new Repetition(r.once,
257: (Element) dispatch(r.element));
258: copy.setLocation(r);
259: return copy;
260: }
261:
262: /** Copy the specified option. */
263: public Option visit(Option o) {
264: Option copy = new Option((Element) dispatch(o.element));
265: copy.setLocation(o);
266: return copy;
267: }
268:
269: /** Copy the specified sequence. */
270: public Sequence visit(Sequence s) {
271: final int size = s.size();
272: Sequence copy = new Sequence(s.name, new ArrayList<Element>(
273: size));
274: copy.setLocation(s);
275: for (int i = 0; i < size; i++) {
276: copy.add((Element) dispatch(s.get(i)));
277: }
278: return copy;
279: }
280:
281: /** Copy the specified followed-by predicate. */
282: public FollowedBy visit(FollowedBy p) {
283: FollowedBy copy = new FollowedBy((Element) dispatch(p.element));
284: copy.setLocation(p);
285: return copy;
286: }
287:
288: /** Copy the specified not-followed-by predicate. */
289: public NotFollowedBy visit(NotFollowedBy p) {
290: NotFollowedBy copy = new NotFollowedBy(
291: (Element) dispatch(p.element));
292: copy.setLocation(p);
293: return copy;
294: }
295:
296: /** Copy the specified semantic predicate. */
297: public SemanticPredicate visit(SemanticPredicate p) {
298: SemanticPredicate copy = new SemanticPredicate(
299: (Action) dispatch(p.element));
300: copy.setLocation(p);
301: return copy;
302: }
303:
304: /** Copy the specified voided element. */
305: public VoidedElement visit(VoidedElement v) {
306: VoidedElement copy = new VoidedElement(
307: (Element) dispatch(v.element));
308: copy.setLocation(v);
309: return copy;
310: }
311:
312: /** Copy the specified binding. */
313: public Binding visit(Binding b) {
314: Binding copy = new Binding(b.name,
315: (Element) dispatch(b.element));
316: copy.setLocation(b);
317: source.add(b);
318: target.add(copy);
319:
320: return copy;
321: }
322:
323: /** Copy the specified string match. */
324: public StringMatch visit(StringMatch m) {
325: StringMatch copy = new StringMatch(m.text,
326: (Element) dispatch(m.element));
327: copy.setLocation(copy);
328:
329: return copy;
330: }
331:
332: /** Copy the specified character class. */
333: public CharClass visit(CharClass c) {
334: CharClass copy = new CharClass(c.exclusive,
335: new ArrayList<CharRange>(c.ranges.size()));
336: copy.setLocation(c);
337: copy.ranges.addAll(c.ranges);
338: return copy;
339: }
340:
341: /** Copy the specified character case. */
342: public CharCase visit(CharCase c) {
343: CharCase copy = new CharCase((CharClass) dispatch(c.klass),
344: (Element) dispatch(c.element));
345: copy.setLocation(c);
346: return copy;
347: }
348:
349: /** Copy the specified character switch. */
350: public CharSwitch visit(CharSwitch s) {
351: final int length = s.cases.size();
352: CharSwitch copy = new CharSwitch(
353: new ArrayList<CharCase>(length));
354: copy.setLocation(s);
355: for (CharCase kase : s.cases) {
356: copy.cases.add((CharCase) dispatch(kase));
357: }
358: copy.base = (Element) dispatch(s.base);
359: return copy;
360: }
361:
362: /** Copy the specified action. */
363: public Action visit(Action a) {
364: Action copy = new Action(new ArrayList<String>(a.code),
365: new ArrayList<Integer>(a.indent));
366: copy.setLocation(a);
367: return copy;
368: }
369:
370: /** Copy the specified parser action. */
371: public ParserAction visit(ParserAction pa) {
372: ParserAction copy = new ParserAction(
373: (Action) dispatch(pa.element));
374: copy.setLocation(pa);
375: return copy;
376: }
377:
378: /** Copy the specified parse tree node. */
379: public ParseTreeNode visit(ParseTreeNode n) {
380: ParseTreeNode copy = new ParseTreeNode(new ArrayList<Binding>(
381: n.predecessors), null, new ArrayList<Binding>(
382: n.successors));
383: copy.setLocation(n);
384: patch(copy.predecessors);
385: if (null != n.node)
386: copy.node = match(n.node);
387: patch(copy.successors);
388:
389: // Done.
390: return copy;
391: }
392:
393: /** Copy the specified binding value. */
394: public BindingValue visit(BindingValue v) {
395: BindingValue copy = new BindingValue(match(v.binding));
396: copy.setLocation(v);
397:
398: // Done.
399: return copy;
400: }
401:
402: /** Copy the specified proper list value. */
403: public ProperListValue visit(ProperListValue v) {
404: ProperListValue copy = new ProperListValue(v.type,
405: new ArrayList<Binding>(v.elements), null);
406: copy.setLocation(v);
407: patch(copy.elements);
408: if (null != v.tail)
409: copy.tail = match(v.tail);
410:
411: // Done.
412: return copy;
413: }
414:
415: /** Copy the specified action base value. */
416: public ActionBaseValue visit(ActionBaseValue v) {
417: ActionBaseValue copy = new ActionBaseValue(match(v.list),
418: match(v.seed));
419: copy.setLocation(v);
420:
421: // Done.
422: return copy;
423: }
424:
425: /** Copy the specified generic node value. */
426: public GenericNodeValue visit(GenericNodeValue v) {
427: GenericNodeValue copy = new GenericNodeValue(v.name,
428: new ArrayList<Binding>(v.children),
429: new ArrayList<Binding>(v.formatting));
430: copy.setLocation(v);
431: patch(copy.children);
432: patch(copy.formatting);
433:
434: // Done.
435: return copy;
436: }
437:
438: /** Copy the specified generic action value. */
439: public GenericActionValue visit(GenericActionValue v) {
440: GenericActionValue copy = new GenericActionValue(v.name,
441: v.first, new ArrayList<Binding>(v.children),
442: new ArrayList<Binding>(v.formatting));
443: copy.setLocation(v);
444: patch(copy.children);
445: patch(copy.formatting);
446:
447: // Done.
448: return copy;
449: }
450:
451: /** Copy the specified generic recursion value. */
452: public GenericRecursionValue visit(GenericRecursionValue v) {
453: GenericRecursionValue copy = new GenericRecursionValue(v.name,
454: v.first, new ArrayList<Binding>(v.children),
455: new ArrayList<Binding>(v.formatting), match(v.list));
456: copy.setLocation(v);
457: patch(copy.children);
458: patch(copy.formatting);
459:
460: // Done.
461: return copy;
462: }
463:
464: /**
465: * Visit the specified element. This method provides the default
466: * implementation for nonterminals, terminals (besides character
467: * classes and switches), node markers, null literals, and value
468: * elements (besides properlists, generic node, generic action, and
469: * generic recursion values), which are immutable and not containers
470: * for other elements.
471: */
472: public Element visit(Element e) {
473: return e;
474: }
475:
476: }
|