[serializer/performance] improved performance of node model traversal

this change deprecates EmitterNodeIterator since it relies on 
expensive calls to iNode.getOffset(). 

Furthermore, it simplifies the implementation because 
- lazy behavior does not provide advantages here
- 'allowHidden' and 'passAbsorber' were always false.

Signed-off-by: Moritz Eysholdt <moritz.eysholdt@typefox.io>
This commit is contained in:
Moritz Eysholdt 2016-10-06 16:36:42 +02:00 committed by Moritz Eysholdt
parent b717ec5b87
commit 17a85f155d
4 changed files with 96 additions and 10 deletions

View file

@ -251,9 +251,8 @@ public abstract class AbstractSyntacticSequencer implements ISyntacticSequencer,
protected void acceptNodes(ISynNavigable fromState, INode fromNode, INode toNode) {
RuleCallStack stack = contexts.peek().stack.clone();
EmitterNodeIterator ni = new EmitterNodeIterator(fromNode, toNode, false, false);
while (ni.hasNext()) {
INode next = ni.next();
List<INode> nodes = collectNodes(fromNode, toNode);
for (INode next : nodes) {
List<ISynState> path = fromState.getShortestPathTo((AbstractElement) next.getGrammarElement(), stack);
if (path != null) {
if (path.get(path.size() - 1) instanceof ISynEmitterState)
@ -319,7 +318,7 @@ public abstract class AbstractSyntacticSequencer implements ISyntacticSequencer,
protected List<INode> collectNodes(INode fromNode, INode toNode) {
if (fromNode == null)
return null;
return Lists.newArrayList(new EmitterNodeIterator(fromNode, toNode, false, false));
return EmitterNodeUtil.collectEmitterNodes(fromNode, toNode);
}
protected abstract void emitUnassignedTokens(EObject semanticObject, ISynTransition transition, INode fromNode,

View file

@ -7,6 +7,8 @@
*******************************************************************************/
package org.eclipse.xtext.serializer.sequencer;
import java.util.List;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.nodemodel.INode;
@ -15,20 +17,24 @@ import org.eclipse.xtext.nodemodel.INode;
*/
public class EmitterNodeFinder {
@Deprecated
protected INode toNode;
private List<INode> emitters;
private int index;
public EmitterNodeFinder(INode node) {
this.toNode = node;
this.emitters = EmitterNodeUtil.collectEmitterNodes(node, null);
this.index = 0;
}
public INode next(AbstractElement grammarElement) {
if (toNode == null)
return null;
EmitterNodeIterator ni = new EmitterNodeIterator(toNode, null, false, false);
while (ni.hasNext()) {
INode next = ni.next();
if (next.getGrammarElement() == grammarElement)
for (int i = index; i < emitters.size(); i++) {
INode next = emitters.get(i);
if (next.getGrammarElement() == grammarElement) {
index = i + 1;
return toNode = next;
}
}
return null;
}

View file

@ -21,7 +21,10 @@ import com.google.common.collect.Lists;
/**
* @author Moritz Eysholdt - Initial contribution and API
*
* @deprecated use {@link org.eclipse.xtext.serializer.sequencer.EmitterNodeUtil}
*/
@Deprecated
public class EmitterNodeIterator implements Iterator<INode> {
protected NodeIterator iterator;

View file

@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
* 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
*******************************************************************************/
package org.eclipse.xtext.serializer.sequencer;
import java.util.Collections;
import java.util.List;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.parsetree.reconstr.impl.NodeIterator;
import com.google.common.collect.Lists;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
public class EmitterNodeUtil {
private static boolean isEmitter(INode node, EObject grammarElement) {
if (node instanceof ILeafNode) {
ILeafNode leaf = (ILeafNode) node;
if (leaf.isHidden())
return false;
return true;
} else if (node instanceof ICompositeNode) {
return GrammarUtil.isDatatypeRuleCall(grammarElement) || grammarElement instanceof CrossReference;
}
return false;
}
private static boolean isAbsorber(EObject grammarElement) {
return grammarElement != null && GrammarUtil.isAssigned(grammarElement);
}
public static List<INode> collectEmitterNodes(INode from, INode to) {
if (from == null) {
return Collections.emptyList();
}
TreeIterator<INode> iterator;
if (from == to) {
iterator = from.getAsTreeIterable().iterator();
iterator.next();
} else {
iterator = new NodeIterator(from);
}
List<INode> result = null;
while (iterator.hasNext()) {
INode next = iterator.next();
if (next == to)
break;
EObject grammarElement = next.getGrammarElement();
if (isEmitter(next, grammarElement)) {
if (isAbsorber(grammarElement))
break;
iterator.prune();
if (result == null) {
result = Lists.newArrayList();
}
result.add(next);
}
}
if (result == null) {
return Collections.emptyList();
}
return result;
}
}