/******************************************************************************* * Copyright (c) 2009-2013 CWI * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * * Paul Klint - Paul.Klint@cwi.nl - CWI * * Arnold Lankamp - Arnold.Lankamp@cwi.nl *******************************************************************************/ package org.rascalmpl.interpreter.matching; import java.util.Iterator; import java.util.Stack; import org.rascalmpl.interpreter.types.NonTerminalType; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.IList; import org.rascalmpl.value.IMap; import org.rascalmpl.value.INode; import org.rascalmpl.value.ISet; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IWithKeywordParameters; import org.rascalmpl.value.type.Type; import org.rascalmpl.values.uptr.ITree; import org.rascalmpl.values.uptr.RascalValueFactory; import org.rascalmpl.values.uptr.SymbolAdapter; import org.rascalmpl.values.uptr.TreeAdapter; public class DescendantReader implements Iterator<IValue> { Stack<Object> spine = new Stack<Object>(); private boolean debug = false; // is set to true when the descendant reader is allowed to skip layout nodes and do other optimizations private boolean interpretTree; DescendantReader(IValue val, boolean interpretTree){ if (debug) { System.err.println("DescendantReader: " + val); } this.interpretTree = interpretTree; push(val); } public boolean hasNext() { while((spine.size() > 0) && (spine.peek() instanceof Iterator && !((Iterator<?>) spine.peek()).hasNext())){ spine.pop(); } return spine.size() > 0; } public IValue next() { if (spine.peek() instanceof Iterator) { Iterator<?> iter = (Iterator<?>) spine.peek(); if (!iter.hasNext()) { spine.pop(); return next(); } push((IValue) iter.next()); return next(); } return (IValue) spine.pop(); } private void push(IValue v, Iterator<IValue> children){ spine.push(v); spine.push(children); } private void push(IValue v){ Type type = v.getType(); if (type.isNode() || type.isConstructor() || type.isAbstractData()) { if (interpretTree && type.isSubtypeOf(RascalValueFactory.Tree)) { pushConcreteSyntaxNode((ITree) v); return; } INode node = (INode) v; push(v, node.getChildren().iterator()); if (node.mayHaveKeywordParameters()) { pushKeywordParameters(node.asWithKeywordParameters()); } } else if(type.isList()) { push(v, ((IList) v).iterator()); } else if(type.isSet()) { push(v, ((ISet) v).iterator()); } else if(type.isMap()) { push(v, new MapKeyValueIterator((IMap) v)); } else if(type.isTuple()) { push(v, new TupleElementIterator((ITuple) v)); } else { spine.push(v); } } private void pushKeywordParameters(IWithKeywordParameters<? extends INode> node) { for (String name : node.getParameterNames()) { push(node.getParameter(name)); } } private void pushConcreteSyntaxNode(ITree tree){ if (debug) System.err.println("pushConcreteSyntaxNode: " + tree); if (TreeAdapter.isChar(tree) || TreeAdapter.isCycle(tree) || TreeAdapter.isLiteral(tree) || TreeAdapter.isCILiteral(tree)) { spine.push(tree); return; // do not recurse } if (TreeAdapter.isAmb(tree)) { // only recurse for (IValue alt : TreeAdapter.getAlternatives(tree)) { pushConcreteSyntaxNode((ITree) alt); } return; } NonTerminalType ctype = (NonTerminalType) tree.getType(); if (debug) System.err.println("ctype.getSymbol=" + ctype.getSymbol()); IConstructor sym = ctype.getSymbol(); if (SymbolAdapter.isAnyList(sym)) { spine.push(tree); int delta = SymbolAdapter.getListSkipDelta(sym); sym = SymbolAdapter.getSymbol(sym); IList listElems = (IList) tree.get(1); if (debug) { for (int i = 0; i < listElems.length(); i++){ System.err.println("#" + i + ": " + listElems.get(i)); } } for (int i = listElems.length() - 1; i >= 0 ; i -= delta){ if (debug) System.err.println("adding: " + listElems.get(i)); pushConcreteSyntaxNode((ITree)listElems.get(i)); } } else if (SymbolAdapter.isStartSort(sym)) { pushConcreteSyntaxNode(TreeAdapter.getStartTop(tree)); } else { if (debug) System.err.println("pushConcreteSyntaxNode: appl"); /* * appl(prod(...), [child0, layout0, child1, ...]) */ spine.push(tree); IList applArgs = (IList) tree.get(1); int delta = (SymbolAdapter.isLex(sym)) ? 1 : 2; // distance between elements for(int i = applArgs.length() - 1; i >= 0 ; i -= delta){ //spine.push(applArgs.get(i)); pushConcreteSyntaxNode((ITree) applArgs.get(i)); } } } public void remove() { throw new UnsupportedOperationException("remove from DescendantReader"); } }