001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 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.Iterator;
023: import java.util.List;
024:
025: import xtc.tree.Visitor;
026:
027: import xtc.type.AST;
028: import xtc.type.Type;
029: import xtc.type.Wildcard;
030:
031: import xtc.util.Runtime;
032:
033: /**
034: * Visitor to add lists as semantic values.
035: *
036: * @author Robert Grimm
037: * @version $Revision: 1.8 $
038: */
039: public class ListMaker extends Visitor {
040:
041: /** The marker for synthetic variables. */
042: public static final String MARKER = "l";
043:
044: /** The runtime. */
045: protected final Runtime runtime;
046:
047: /** The analyzer. */
048: protected final Analyzer analyzer;
049:
050: /** The type operations. */
051: protected final AST ast;
052:
053: /** The current production's element type. */
054: protected Type element;
055:
056: /** The list of elements. */
057: protected List<Element> elements;
058:
059: /**
060: * Create a new list maker.
061: *
062: * @param runtime The runtime.
063: * @param analyzer The analyzer.
064: * @param ast The type operations.
065: */
066: public ListMaker(Runtime runtime, Analyzer analyzer, AST ast) {
067: this .runtime = runtime;
068: this .analyzer = analyzer;
069: this .ast = ast;
070: elements = new ArrayList<Element>();
071: }
072:
073: /** Visit the specified module. */
074: public void visit(Module m) {
075: // Initialize the per-grammar state.
076: analyzer.register(this );
077: analyzer.init(m);
078: elements.clear();
079:
080: // Process the productions.
081: for (Production p : m.productions) {
082: if (AST.isList(p.type)) {
083: // Initialize the element type.
084: if (runtime.test("optionVariant")
085: && AST.isDynamicNode(AST.getArgument(p.type))) {
086: element = Wildcard.TYPE;
087: } else {
088: element = null;
089: }
090:
091: // Actually process the production.
092: analyzer.process(p);
093:
094: // Patch the production's type.
095: if ((null != element) && !element.isError()) {
096: p.type = AST.listOf(ast.concretize(element,
097: AST.NULL_NODE));
098: }
099: }
100: }
101: }
102:
103: /** Visit the specified full production. */
104: public void visit(FullProduction p) {
105: dispatch(p.choice);
106: }
107:
108: /** Visit the specified choice. */
109: public void visit(OrderedChoice c) {
110: for (Sequence alt : c.alternatives)
111: dispatch(alt);
112: }
113:
114: /** Visit the specified sequence. */
115: public void visit(Sequence s) {
116: // Remember the current number of elements.
117: final int base = elements.size();
118:
119: // Process the elements of the sequence.
120: for (Iterator<Element> iter = s.elements.iterator(); iter
121: .hasNext();) {
122: Element e = iter.next();
123:
124: if ((!iter.hasNext()) && (e instanceof OrderedChoice)) {
125: // Continue with the trailing choice.
126: dispatch(e);
127: } else {
128: // Add the current element to the list of traversed elements.
129: elements.add(e);
130: }
131: }
132:
133: // If we have no trailing choice and the elements do not set the
134: // semantic value, we need to add a semantic value.
135: if ((!s.hasTrailingChoice())
136: && (!Analyzer.setsValue(elements, false))) {
137: List<Binding> bindings = new ArrayList<Binding>();
138:
139: // Iterate over the elements and collect all bindable elements.
140: for (int i = 0; i < elements.size(); i++) {
141: Element e = elements.get(i);
142:
143: if (e instanceof Binding) {
144: bindings.add((Binding) e);
145: } else if (analyzer.isBindable(e)) {
146: Binding b = new Binding(analyzer.variable(MARKER),
147: e);
148: elements.set(i, b);
149: bindings.add(b);
150: }
151: }
152:
153: // Update the element type.
154: if ((null != element) && !element.isError()) {
155: for (Binding b : bindings) {
156: Type t = analyzer.type(b.element);
157: if (AST.isList(t))
158: t = AST.getArgument(t);
159:
160: Type u = ast.unify(element, t, true);
161: if (u.isError()) {
162: runtime
163: .error(
164: "unable to determine consistent list element type",
165: s);
166: runtime.errConsole().loc(s).p(
167: ": error: 1st type is '");
168: ast.print(element, runtime.errConsole(), false,
169: true, null);
170: runtime.errConsole().pln("'");
171: runtime.errConsole().loc(s).p(
172: ": error: 2nd type is '");
173: ast.print(t, runtime.errConsole(), false, true,
174: null);
175: runtime.errConsole().pln("'").flush();
176: }
177: element = u;
178: }
179: }
180:
181: // Ensure the alternative has a semantic value.
182: if (0 == bindings.size()) {
183: // An empty list value.
184: s.add(EmptyListValue.VALUE);
185: } else if ((1 == bindings.size())
186: && AST.isList(analyzer
187: .type(bindings.get(0).element))) {
188: // The only binding already has a list value. Pass it through.
189: Binding b = bindings.get(0);
190: if (Analyzer.isSynthetic(b.name)) {
191: // Rename the binding.
192: b.name = CodeGenerator.VALUE;
193: } else {
194: // Preserve the user-specified variable name. Note that the
195: // bindings name cannot be yyValue due to the
196: // Analyzer.setValue() test above.
197: s.add(new BindingValue(b));
198: }
199:
200: } else {
201: // Check whether the last binding has a list value.
202: Binding last = bindings.get(bindings.size() - 1);
203:
204: if (AST.isList(analyzer.type(last.element))) {
205: bindings.remove(bindings.size() - 1);
206: s.add(new ProperListValue(analyzer.current().type,
207: bindings, last));
208: } else {
209: s.add(new ProperListValue(analyzer.current().type,
210: bindings, null));
211: }
212: }
213: }
214:
215: // Patch back any added binding.
216: int size = s.size();
217:
218: if (s.hasTrailingChoice()
219: || ((0 != size) && (s.get(size - 1) instanceof ValueElement))) {
220: // Ignore trailing choices and value elements.
221: size--;
222: }
223:
224: for (int i = 0; i < size; i++) {
225: Element e = elements.get(base + i);
226: if (s.get(i) != e)
227: s.elements.set(i, e);
228: }
229:
230: // Remove any elements added by processing the sequence.
231: if (0 == base) {
232: elements.clear();
233: } else {
234: elements.subList(base, elements.size()).clear();
235: }
236: }
237:
238: }
|