package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.traverse;
import java.util.Iterator;
import java.util.Map.Entry;
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.IString;
import org.rascalmpl.value.ITuple;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.IValueFactory;
import org.rascalmpl.value.IWithKeywordParameters;
import org.rascalmpl.values.uptr.ITree;
import org.rascalmpl.values.uptr.TreeAdapter;
public class TraverseOnceNoRebuild extends TraverseOnce implements ITraverseSpecialization {
public TraverseOnceNoRebuild(IValueFactory vf) {
super(vf);
}
@Override
public
IValue traverseTupleOnce(IValue subject, final TraversalState tr) {
ITuple tuple = (ITuple) subject;
int arity = tuple.arity();
boolean hasMatched = false;
boolean hasChanged = false;
for (int i = 0; i < arity; i++){
tr.setMatchedAndChanged(false, false);
tr.traverse.once(tuple.get(i), tr);
hasMatched |= tr.hasMatched();
hasChanged |= tr.hasChanged();
}
tr.setMatchedAndChanged(hasMatched, hasChanged);
return subject;
}
@Override
public
IValue traverseADTOnce(IValue subject, final TraversalState tr) {
IConstructor cons = (IConstructor)subject;
boolean hasKwParams = false;
int arity = cons.arity();
if (cons.mayHaveKeywordParameters() && cons.asWithKeywordParameters().hasParameters()) {
hasKwParams = true;
}
if (arity == 0 && !hasKwParams) {
return subject; // constants have no children to traverse into
}
boolean hasChanged = false;
boolean hasMatched = false;
for (int i = 0; i < arity; i++){
IValue child = cons.get(i);
tr.setMatchedAndChanged(false, false);
child = tr.traverse.once(child, tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
if (hasKwParams) {
IWithKeywordParameters<? extends INode> consKw = cons.asWithKeywordParameters();
for (String kwName : consKw.getParameterNames()) {
IValue val = consKw.getParameter(kwName);
tr.setMatchedAndChanged(false, false);
tr.traverse.once(val, tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
}
tr.setMatchedAndChanged(hasMatched, hasChanged);
return subject;
}
@Override
public
IValue traverseConcreteTreeOnce(IValue subject, final TraversalState tr) {
ITree tree = (ITree)subject;
// Only visit non-layout nodes in argument list
IList list = TreeAdapter.getArgs(tree);
int len = list.length();
if (len > 0) {
boolean hasChanged = false;
boolean hasMatched = false;
boolean isTop = TreeAdapter.isTop(tree);
if (isTop) {
tr.setMatchedAndChanged(false, false);
tr.traverse.once(list.get(1), tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
else {
for (int i = 0; i < len; i++){
IValue elem = list.get(i);
if (i % 2 == 0) { // Recursion to all non-layout elements
tr.setMatchedAndChanged(false, false);
tr.traverse.once(elem, tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
}
}
tr.setMatchedAndChanged(hasMatched, hasChanged);
}
return subject;
}
@Override
public
IValue traverseMapOnce(IValue subject, final TraversalState tr) {
IMap map = (IMap) subject;
if(!map.isEmpty()){
Iterator<Entry<IValue,IValue>> iter = map.entryIterator();
boolean hasChanged = false;
boolean hasMatched = false;
while (iter.hasNext()) {
Entry<IValue,IValue> entry = iter.next();
tr.setMatchedAndChanged(false, false);
tr.traverse.once(entry.getKey(), tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
tr.setMatchedAndChanged(false, false);
tr.traverse.once(entry.getValue(), tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
tr.setMatchedAndChanged(hasMatched, hasChanged);
return subject;
} else {
return subject;
}
}
@Override
public
IValue traverseSetOnce(IValue subject, final TraversalState tr) {
ISet set = (ISet) subject;
if(!set.isEmpty()){
boolean hasChanged = false;
boolean hasMatched = false;
for (IValue v : set) {
tr.setMatchedAndChanged(false, false);
tr.traverse.once(v, tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
tr.setMatchedAndChanged(hasMatched, hasChanged);
return subject;
} else {
return subject;
}
}
@Override
public
IValue traverseListOnce(IValue subject, final TraversalState tr) {
IList list = (IList) subject;
int len = list.length();
if (len > 0){
boolean hasChanged = false;
boolean hasMatched = false;
for (int i = 0; i < len; i++){
IValue elem = list.get(i);
tr.setMatchedAndChanged(false, false);
tr.traverse.once(elem, tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
tr.setMatchedAndChanged(hasMatched, hasChanged);
return subject;
} else {
return subject;
}
}
@Override
public
IValue traverseNodeOnce(IValue subject, final TraversalState tr) {
IValue result= subject;
INode node = (INode)subject;
int arity = node.arity();
boolean hasKwParams = false;
if(node.mayHaveKeywordParameters() && node.asWithKeywordParameters().hasParameters()){
hasKwParams = true;
}
if (arity == 0 && !hasKwParams){
result = subject;
}
boolean hasChanged = false;
boolean hasMatched = false;
for (int i = 0; i < arity; i++){
IValue child = node.get(i);
tr.setMatchedAndChanged(false, false);
tr.traverse.once(child, tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
if (hasKwParams) {
IWithKeywordParameters<? extends INode> nodeKw = node.asWithKeywordParameters();
for (String kwName : nodeKw.getParameterNames()) {
IValue val2 = nodeKw.getParameter(kwName);
tr.setMatchedAndChanged(false, false);
tr.traverse.once(val2, tr);
hasChanged |= tr.hasChanged();
hasMatched |= tr.hasMatched();
}
}
tr.setMatchedAndChanged(hasMatched, hasChanged);
return result;
}
@Override
public
IValue traverseStringOnce(IValue subject, final TraversalState tr) {
boolean hasMatched = tr.hasMatched();
boolean hasChanged = tr.hasChanged();
tr.setMatchedAndChanged(false, false);
IValue res = traverseString(subject, tr);
tr.setMatchedAndChanged(tr.hasMatched() | hasMatched,
tr.hasChanged() | hasChanged);
return res;
}
/*
* traverseString implements a visit of a string subject by visiting subsequent substrings
* subject[0,len], subject[1,len] ...and trying to match the cases. If a case matches
* the subject cursor is advanced by the length of the match and the matched substring may be replaced.
*
* Performance issue: we create a lot of garbage by producing all these substrings.
*/
private IValue traverseString(IValue subject, final TraversalState tr){
IString subjectIString = (IString) subject;
int len = subjectIString.length();
int subjectCursor = 0;
boolean hasMatched = false;
boolean hasChanged = false;
while (subjectCursor < len){
tr.setMatchedAndChanged(false, false);
tr.setBegin(subjectCursor);
tr.setEnd(len);
traverseTop(subject, tr);
if(tr.hasMatched()){
subjectCursor = tr.getEnd();
} else {
subjectCursor++;
}
hasMatched |= tr.hasMatched();
hasChanged |= tr.hasChanged();
}
tr.setMatchedAndChanged(tr.hasMatched() | hasMatched,
tr.hasChanged() | hasChanged);
return subject;
}
}