From 53838b74af797525c162d6f249cb46f9a3d82c76 Mon Sep 17 00:00:00 2001 From: jkohnlein Date: Thu, 3 Jul 2008 12:17:22 +0000 Subject: [PATCH] partial parsing revisited EContentAdapter for offset und line --- .../src/org/eclipse/xtext/util/MultiMap.java | 47 ++++ .../org.eclipse.xtext/model/parsetree.ecore | 21 +- .../parser/antlr/AbstractAntlrParser.java | 76 ++++-- .../xtext/parser/antlr/XtextTokenStream.java | 23 ++ .../impl/EnclosingCompositeNodeFinder.java | 8 +- .../parser/impl/NodeWithCachedOffset.java | 2 +- .../parser/impl/PartialParsingPointers.java | 14 +- .../xtext/parser/impl/PartialParsingUtil.java | 242 ++++++------------ .../xtext/parsetree/NodeContentAdapter.java | 123 +++++++++ .../org/eclipse/xtext/parsetree/NodeUtil.java | 9 +- .../xtext/parsetree/impl/ParsetreeUtil.java | 26 +- .../eclipse/xtext/resource/XtextResource.java | 9 + .../ParseErrorHandlingTest.java | 8 +- .../parser/AbstractPartialParserTest.java | 2 +- .../eclipse/xtext/parser/LookaheadTest.java | 52 ---- .../parser/PartialParserReplaceTest.java | 6 +- .../parser/PartialParsingPerformanceTest.java | 35 ++- .../parser/PartialParsingPointerTest.java | 64 ++++- .../xtext/parsetree/LengthOffsetLineTest.java | 50 ++-- .../parsetree/NodeContentAdapterTest.java | 25 ++ .../reconstr/ComplexReconstrTest.java | 2 - .../xtext/reference/LeafNodeBug_234132.java | 6 +- 22 files changed, 523 insertions(+), 327 deletions(-) create mode 100644 plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/MultiMap.java create mode 100644 plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/NodeContentAdapter.java delete mode 100644 tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/LookaheadTest.java create mode 100644 tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/NodeContentAdapterTest.java diff --git a/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/MultiMap.java b/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/MultiMap.java new file mode 100644 index 000000000..e1381526e --- /dev/null +++ b/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/MultiMap.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2008 itemis AG (http://www.itemis.eu) 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.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +/** + * @author Jan Köhnlein - Initial contribution and API + * + */ +public class MultiMap extends HashMap>{ + + private static final long serialVersionUID = 28768781263L; + + public void put(K key, V value) { + List list = super.get(key); + if(list == null) { + list=new ArrayList(); + put(key, list); + } + list.add(value); + } + + public boolean remove(K key, V value) { + List list = super.get(key); + if(list == null) return false; + boolean result = list.remove(value); + if(list.isEmpty()) { + remove(key); + } + return result; + } + + public List get(K key) { + List list = super.get(key); + return (list == null) ? Collections.emptyList() : list; + } +} diff --git a/plugins/org.eclipse.xtext/model/parsetree.ecore b/plugins/org.eclipse.xtext/model/parsetree.ecore index c8c11660c..4d971b09c 100755 --- a/plugins/org.eclipse.xtext/model/parsetree.ecore +++ b/plugins/org.eclipse.xtext/model/parsetree.ecore @@ -6,8 +6,8 @@ - - + @@ -15,16 +15,6 @@
- - -
- - - - -
- -
@@ -46,12 +36,19 @@
+ + +
+ + + + diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/AbstractAntlrParser.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/AbstractAntlrParser.java index 35e1d310b..c09233c4c 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/AbstractAntlrParser.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/AbstractAntlrParser.java @@ -39,6 +39,7 @@ import org.eclipse.xtext.parsetree.NodeAdapter; import org.eclipse.xtext.parsetree.NodeAdapterFactory; import org.eclipse.xtext.parsetree.ParsetreeFactory; import org.eclipse.xtext.parsetree.SyntaxError; +import org.eclipse.xtext.util.MultiMap; import org.eclipse.xtext.util.Strings; public abstract class AbstractAntlrParser extends Parser { @@ -53,6 +54,9 @@ public abstract class AbstractAntlrParser extends Parser { protected int lastConsumedIndex = -1; + private MultiMap deferredLookaheadMap = new MultiMap(); + private Map token2NodeMap = new HashMap(); + protected AbstractAntlrParser(TokenStream input) { super(input); } @@ -97,8 +101,7 @@ public abstract class AbstractAntlrParser extends Parser { leafNode.setFeature(feature); parentNode.getChildren().add(leafNode); lastConsumedIndex = token.getTokenIndex(); - ((XtextTokenStream) input).consumeLookahead(); - // ((XtextTokenStream) input).decrementLookahead(); + tokenConsumed(token, leafNode); return leafNode; } return null; @@ -130,7 +133,8 @@ public abstract class AbstractAntlrParser extends Parser { antlrTypeToLexerName.put(Integer.parseInt(tokenTypeId), token.substring(prefix.length())); line = br.readLine(); } - } catch (IOException e) { + } + catch (IOException e) { log.error(e); throw new WrappedException(e); } @@ -184,7 +188,8 @@ public abstract class AbstractAntlrParser extends Parser { EList leafNodes = currentNode.getLeafNodes(); if (leafNodes.isEmpty()) { appendError(currentNode); - } else { + } + else { appendError(leafNodes.get(leafNodes.size() - 1)); } } @@ -268,7 +273,8 @@ public abstract class AbstractAntlrParser extends Parser { try { Method method = this.getClass().getMethod(antlrEntryRuleName); current = (EObject) method.invoke(this); - } catch (InvocationTargetException ite) { + } + catch (InvocationTargetException ite) { Throwable targetException = ite.getTargetException(); if (targetException instanceof RecognitionException) { throw (RecognitionException) targetException; @@ -277,14 +283,17 @@ public abstract class AbstractAntlrParser extends Parser { throw new WrappedException((Exception) targetException); } throw new RuntimeException(targetException); - } catch (Exception e) { + } + catch (Exception e) { throw new WrappedException(e); } appendTrailingHiddenTokens(currentNode); - } finally { + } + finally { try { appendAllTokens(); - } finally { + } + finally { result = new ParseResult(current, currentNode); } } @@ -296,15 +305,28 @@ public abstract class AbstractAntlrParser extends Parser { if (!entryRuleName.startsWith("entryRule")) { if (!entryRuleName.startsWith("rule")) { antlrEntryRuleName = "entryRule" + entryRuleName; - } else { + } + else { antlrEntryRuleName = "entry" + Strings.toFirstUpper(entryRuleName); } - } else { + } + else { antlrEntryRuleName = entryRuleName; } return antlrEntryRuleName; } + private void tokenConsumed(Token token, LeafNode leafNode) { + List nodesDecidingOnToken = deferredLookaheadMap.get(token); + for (CompositeNode nodeDecidingOnToken : nodesDecidingOnToken) { + nodeDecidingOnToken.getLookaheadLeafNodes().add(leafNode); + } + deferredLookaheadMap.remove(token); + token2NodeMap.put(token, leafNode); + ((XtextTokenStream) input).consumeLookahead(); + // ((XtextTokenStream) input).decrementLookahead(); + } + /** * The current lookahead is the number of tokens that have been matched by * the parent rule to decide that the current rule has to be called. @@ -313,24 +335,39 @@ public abstract class AbstractAntlrParser extends Parser { */ protected void setCurrentLookahead() { XtextTokenStream xtextTokenStream = (XtextTokenStream) input; - currentNode.setLookahead(xtextTokenStream.getCurrentLookahead()); - currentNode.setLookaheadConsumed(xtextTokenStream.getLookaheadConsumedByParent()); + List lookaheadTokens = xtextTokenStream.getLookaheadTokens(); + for (Token lookaheadToken : lookaheadTokens) { + LeafNode leafNode = token2NodeMap.get(lookaheadToken); + if (leafNode == null) { + deferredLookaheadMap.put(lookaheadToken, currentNode); + } + else { + currentNode.getLookaheadLeafNodes().add(leafNode); + } + } } /** - * Sets the current lookahead to zero. See {@link - * AbstractAntlrParser#setCurrentLookahead()} + * Sets the current lookahead to zero. See + * {@link AbstractAntlrParser#setCurrentLookahead()} */ protected void resetLookahead() { XtextTokenStream xtextTokenStream = (XtextTokenStream) input; xtextTokenStream.resetLookahead(); + token2NodeMap.clear(); } protected void moveLookaheadInfo(CompositeNode source, CompositeNode target) { - target.setLookahead(source.getLookahead()); - target.setLookaheadConsumed(source.getLookaheadConsumed()); - source.setLookahead(0); - source.setLookaheadConsumed(0); + EList sourceLookaheadLeafNodes = source.getLookaheadLeafNodes(); + target.getLookaheadLeafNodes().addAll(sourceLookaheadLeafNodes); + sourceLookaheadLeafNodes.clear(); + + for (Token deferredLookaheadToken : deferredLookaheadMap.keySet()) { + List nodesDecidingOnToken = deferredLookaheadMap.get(deferredLookaheadToken); + while(nodesDecidingOnToken.indexOf(source) != -1) { + nodesDecidingOnToken.set(nodesDecidingOnToken.indexOf(source), target); + } + } } /** @@ -339,11 +376,12 @@ public abstract class AbstractAntlrParser extends Parser { * {@link AbstractAntlrParser#setCurrentLookahead()} * * @see org.antlr.runtime.BaseRecognizer#match(org.antlr.runtime.IntStream, - * int, org.antlr.runtime.BitSet) + * int, org.antlr.runtime.BitSet) */ @Override public void match(IntStream input, int ttype, BitSet follow) throws RecognitionException { super.match(input, ttype, follow); + ((XtextTokenStream) input).removeLastLookaheadToken(); ((XtextTokenStream) input).decrementLookahead(); } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/XtextTokenStream.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/XtextTokenStream.java index 569305c95..cfbb91868 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/XtextTokenStream.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/XtextTokenStream.java @@ -8,7 +8,11 @@ *******************************************************************************/ package org.eclipse.xtext.parser.antlr; +import java.util.ArrayList; +import java.util.List; + import org.antlr.runtime.CommonTokenStream; +import org.antlr.runtime.Token; import org.antlr.runtime.TokenSource; /** @@ -21,6 +25,8 @@ public class XtextTokenStream extends CommonTokenStream { private int currentLookahead; private int lookaheadConsumedByParent; + private List lookaheadTokens = new ArrayList(); + public XtextTokenStream() { super(); } @@ -41,6 +47,10 @@ public class XtextTokenStream extends CommonTokenStream { @Override public int LA(int i) { currentLookahead = Math.max(currentLookahead, i); + Token lookaheadToken = LT(i); + if(!lookaheadTokens.contains(lookaheadToken)) { + lookaheadTokens.add(lookaheadToken); + } return super.LA(i); } @@ -51,6 +61,17 @@ public class XtextTokenStream extends CommonTokenStream { return currentLookahead; } + /** + * @return the lookaheadTokens + */ + public List getLookaheadTokens() { + return lookaheadTokens; + } + + public void removeLastLookaheadToken() { + lookaheadTokens.remove(lookaheadTokens.size()-1); + } + /** * @return the lookaheadConsumedByParent */ @@ -61,6 +82,7 @@ public class XtextTokenStream extends CommonTokenStream { public void resetLookahead() { currentLookahead = 0; lookaheadConsumedByParent = 0; + lookaheadTokens.clear(); } public void decrementLookahead() { @@ -70,4 +92,5 @@ public class XtextTokenStream extends CommonTokenStream { public void consumeLookahead() { ++lookaheadConsumedByParent; } + } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/EnclosingCompositeNodeFinder.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/EnclosingCompositeNodeFinder.java index b3abb7a86..e81c28db2 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/EnclosingCompositeNodeFinder.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/EnclosingCompositeNodeFinder.java @@ -24,12 +24,12 @@ public class EnclosingCompositeNodeFinder { private int currentOffset = 0; private int startTokenParentIndex = -1; - private List nodesEnclosingRegion; + private List nodesEnclosingRegion; private int offset; private int length; public EnclosingCompositeNodeFinder(CompositeNode parentNode, int offset, int length) { - nodesEnclosingRegion = new ArrayList(); + nodesEnclosingRegion = new ArrayList(); this.offset = offset; this.length = length; findRegion(parentNode); @@ -38,13 +38,13 @@ public class EnclosingCompositeNodeFinder { /** * @return the nodesEnclosingRegion */ - public List getNodesEnclosingRegion() { + public List getNodesEnclosingRegion() { return nodesEnclosingRegion; } private boolean findRegion(CompositeNode parentNode) { boolean isLookingForStartToken = startTokenParentIndex == -1; - nodesEnclosingRegion.add(new NodeWithCachedOffset(currentOffset, parentNode)); + nodesEnclosingRegion.add(parentNode); int currentParentIndex = nodesEnclosingRegion.size() - 1; EList children = parentNode.getChildren(); for (AbstractNode child : children) { diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/NodeWithCachedOffset.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/NodeWithCachedOffset.java index ff6fe4c29..be3d0d1d5 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/NodeWithCachedOffset.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/NodeWithCachedOffset.java @@ -28,7 +28,7 @@ public class NodeWithCachedOffset { /** * @return the offset */ - public int getChachedOffset() { + public int getCachedOffset() { return offset; } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/PartialParsingPointers.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/PartialParsingPointers.java index aee05b1d1..71f33c5aa 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/PartialParsingPointers.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/PartialParsingPointers.java @@ -34,21 +34,21 @@ public class PartialParsingPointers { private int length; private int offset; private List validReplaceRootNodes; - private List nodesEnclosingChangeRegion; + private List nodesEnclosingChangeRegion; public PartialParsingPointers(CompositeNode rootNode, int offset, int length, - List validReplaceRootNodes, List nodesEnclosingChangeRegion) { + List validReplaceRootNodes, List nodesEnclosingRegion) { if (validReplaceRootNodes == null || validReplaceRootNodes.isEmpty()) { throw new IllegalArgumentException("validReplaceRootNodes cannot be empty"); } - if (nodesEnclosingChangeRegion == null || nodesEnclosingChangeRegion.isEmpty()) { + if (nodesEnclosingRegion == null || nodesEnclosingRegion.isEmpty()) { throw new IllegalArgumentException("nodesEnclosingChangeRegion cannot be empty"); } this.rootNode = rootNode; this.offset = offset; this.length = length; this.validReplaceRootNodes = validReplaceRootNodes; - this.nodesEnclosingChangeRegion = nodesEnclosingChangeRegion; + this.nodesEnclosingChangeRegion = nodesEnclosingRegion; } public String findReparseRegion() { @@ -92,12 +92,12 @@ public class PartialParsingPointers { public EObject findASTReplaceElement(CompositeNode replaceRootNode) { boolean foundReplaceNode = false; for (int i = 0; i < nodesEnclosingChangeRegion.size(); ++i) { - CompositeNode nodeEnclosingRegion = (CompositeNode) nodesEnclosingChangeRegion.get(i).getNode(); + CompositeNode nodeEnclosingRegion = nodesEnclosingChangeRegion.get(i); if (nodeEnclosingRegion == replaceRootNode) { foundReplaceNode = true; } if (foundReplaceNode) { - EObject currentASTElement = nodesEnclosingChangeRegion.get(i).getNode().getElement(); + EObject currentASTElement = nodesEnclosingChangeRegion.get(i).getElement(); if (currentASTElement != null) { return currentASTElement; } @@ -107,7 +107,7 @@ public class PartialParsingPointers { // In this case, there must not be any composite nodes with // multiple composite children on the way down. return NodeUtil.getASTElementForRootNode((CompositeNode) nodesEnclosingChangeRegion.get( - nodesEnclosingChangeRegion.size() - 1).getNode()); + nodesEnclosingChangeRegion.size() - 1)); } public String findASTContainmentFeatureName() { diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/PartialParsingUtil.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/PartialParsingUtil.java index ac7a10b24..b8dff66c2 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/PartialParsingUtil.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parser/impl/PartialParsingUtil.java @@ -101,7 +101,7 @@ public class PartialParsingUtil { public static String insertChangeIntoReplaceRegion(CompositeNode replaceRootNode, int originalOffset, int originalLength, String changedRegion) { String originalRegion = replaceRootNode.serialize(); - int changeOffset = originalOffset - replaceRootNode.offset(); + int changeOffset = originalOffset - replaceRootNode.getOffset(); StringBuffer reparseRegion = new StringBuffer(); reparseRegion.append(originalRegion.substring(0, changeOffset)); reparseRegion.append(changedRegion); @@ -110,7 +110,7 @@ public class PartialParsingUtil { } public static PartialParsingPointers calculatePartialParsingPointers(CompositeNode rootNode, int offset, int length) { - List nodesEnclosingRegion = collectNodesEnclosingChangeRegion(rootNode, offset, length); + List nodesEnclosingRegion = collectNodesEnclosingChangeRegion(rootNode, offset, length); List validReplaceRootNodes = internalFindValidReplaceRootNodeForChangeRegion( nodesEnclosingRegion, offset, length); if (validReplaceRootNodes.isEmpty()) { @@ -122,11 +122,30 @@ public class PartialParsingUtil { /** * Collects a list of all nodes containing the change region */ - private static List collectNodesEnclosingChangeRegion(CompositeNode parent, int offset, - int length) { - EnclosingCompositeNodeFinder enclosingCompositeNodeFinder = new EnclosingCompositeNodeFinder(parent, offset, - length); - return enclosingCompositeNodeFinder.getNodesEnclosingRegion(); + private static List collectNodesEnclosingChangeRegion(CompositeNode parent, int offset, int length) { + List nodesEnclosingRegion = new ArrayList(); + if (nodeEnclosesRegion(parent, offset, length)) { + collectNodesEnclosingChangeRegion(parent, offset, length, nodesEnclosingRegion); + } + return nodesEnclosingRegion; + } + + private static void collectNodesEnclosingChangeRegion(CompositeNode parent, int offset, int length, + List nodesEnclosingRegion) { + nodesEnclosingRegion.add(parent); + for (AbstractNode child : parent.getChildren()) { + if (child instanceof CompositeNode) { + CompositeNode childCompositeNode = (CompositeNode) child; + if (nodeEnclosesRegion(childCompositeNode, offset, length)) { + collectNodesEnclosingChangeRegion(childCompositeNode, offset, length, nodesEnclosingRegion); + break; + } + } + } + } + + private static boolean nodeEnclosesRegion(CompositeNode node, int offset, int length) { + return node.getOffset() <= offset && node.getOffset() + node.length() >= offset + length; } /** @@ -141,167 +160,72 @@ public class PartialParsingUtil { * @return */ private static List internalFindValidReplaceRootNodeForChangeRegion( - List nodesEnclosingRegion, int offset, int length) { - List lookaheadNodes = new ArrayList(); - int numConsumedLookaheadTokens = 0; + List nodesEnclosingRegion, int offset, int length) { + List lookaheadNodes = new ArrayList(); List validReplaceRootNodes = new ArrayList(); - for (NodeWithCachedOffset node : nodesEnclosingRegion) { - List parentsLookaheadNodes = getParentsLookaheadNodes(node); + boolean lookaheadChanged = false; + for (CompositeNode node : nodesEnclosingRegion) { + // EList parentsLookaheadNodes = ((CompositeNode) + // node.getNode()).getLookaheadLeafNodes(); + EList parentsLookaheadNodes = node.getLookaheadLeafNodes(); if (!parentsLookaheadNodes.isEmpty()) { - mergeLookaheadNodes(lookaheadNodes, parentsLookaheadNodes); - } - if (((CompositeNode) node.getNode()).getLookaheadConsumed() > 0) { - // parent has consumed lookahead tokens. - numConsumedLookaheadTokens += ((CompositeNode) node.getNode()).getLookaheadConsumed(); - if (numConsumedLookaheadTokens == lookaheadNodes.size()) { - // parent has consumed all current lookahead tokens - NodeWithCachedOffset leafNode = lookaheadNodes.get(numConsumedLookaheadTokens - 1); - if (nodeIsBeforeRegion(leafNode, offset)) { - // last lookahead token is before changed region - //NodeUtil.dumpCompositeNodeInfo("Possible entry node: " - // , node); - validReplaceRootNodes.add((CompositeNode) node.getNode()); + int index = lookaheadNodes.indexOf(parentsLookaheadNodes.get(0)); + if (index > 0) { + // remove lookahead nodes common with grandpa + while (lookaheadNodes.size() > index) { + lookaheadNodes.remove(index); } } + lookaheadNodes.addAll(parentsLookaheadNodes); + lookaheadChanged = true; } + if (lookaheadChanged) { + LeafNode lastLookaheadLeafNode = lookaheadNodes.get(lookaheadNodes.size() - 1); + if (nodeIsBeforeRegion(lastLookaheadLeafNode, offset)) { + // last lookahead token is before changed region + // and parent has consumed all current lookahead tokens + // NodeUtil.dumpCompositeNodeInfo("Possible entry node: " + // , node); + validReplaceRootNodes.add(node); + lookaheadChanged = false; + } + } + // List lookaheadNodes = new + // ArrayList(); + // int numConsumedLookaheadTokens = 0; + // List validReplaceRootNodes = new + // ArrayList(); + // + // for (NodeWithCachedOffset node : nodesEnclosingRegion) { + // List parentsLookaheadNodes = + // getParentsLookaheadNodes(node); + // if (!parentsLookaheadNodes.isEmpty()) { + // mergeLookaheadNodes(lookaheadNodes, parentsLookaheadNodes); + // } + // if (((CompositeNode) node.getNode()).getLookaheadConsumed() > 0) + // { + // // parent has consumed lookahead tokens. + // numConsumedLookaheadTokens += ((CompositeNode) + // node.getNode()).getLookaheadConsumed(); + // if (numConsumedLookaheadTokens == lookaheadNodes.size()) { + // // parent has consumed all current lookahead tokens + // NodeWithCachedOffset leafNode = + // lookaheadNodes.get(numConsumedLookaheadTokens - 1); + // if (nodeIsBeforeRegion(leafNode, offset)) { + // // last lookahead token is before changed region + // //NodeUtil.dumpCompositeNodeInfo("Possible entry node: " + // // , node); + // validReplaceRootNodes.add((CompositeNode) node.getNode()); + // } + // } + // } } return validReplaceRootNodes; } - private static void mergeLookaheadNodes(List lookaheadNodes, - List parentsLookaheadNodes) { - NodeWithCachedOffset firstParentLookaheadNode = parentsLookaheadNodes.get(0); - int index; - for(index=0; index < lookaheadNodes.size(); ++index) { - if(lookaheadNodes.get(index).getNode().equals(firstParentLookaheadNode.getNode())) { - break; - } - } - if (index < lookaheadNodes.size()) { - // remove lookahead nodes common with grandpa - while (lookaheadNodes.size() > index) { - lookaheadNodes.remove(index); - } - } - lookaheadNodes.addAll(parentsLookaheadNodes); + private static boolean nodeIsBeforeRegion(LeafNode node, int offset) { + return node.getOffset() + node.length() <= offset; } - private static boolean nodeIsBeforeRegion(NodeWithCachedOffset leafNode, int offset) { - return leafNode.getChachedOffset() + leafNode.getNode().length() <= offset; - } - - private static List getParentsLookaheadNodes(NodeWithCachedOffset child) { - int lookaheadFromParent = ((CompositeNode) child.getNode()).getLookahead(); - if (lookaheadFromParent != 0) { - List lookaheadNodes = new ArrayList(); - int consumedByParent = ((CompositeNode) child.getNode()).getLookaheadConsumed(); - if (consumedByParent > 0) { - // some lookahead nodes are consumed by parent - NodeWithCachedOffset tempLeaf = child; - for (int i = 0; i < consumedByParent; ++i) { - tempLeaf = previousUnhiddenLeaf(tempLeaf.getNode(), tempLeaf.getChachedOffset()); - lookaheadNodes.add(tempLeaf); - } - } - if (lookaheadFromParent - consumedByParent > 0) { - // remaining lookahead nodes consumed by child - NodeWithCachedOffset tempLeaf = child; - for (int i = 0; i < lookaheadFromParent - consumedByParent; ++i) { - tempLeaf = nextUnhiddenLeaf(tempLeaf.getNode(), tempLeaf.getChachedOffset()); - lookaheadNodes.add(tempLeaf); - } - } - return lookaheadNodes; - } - else { - return Collections. emptyList(); - } - } - - private static NodeWithCachedOffset nextUnhiddenLeaf(AbstractNode node, int currentOffset) { - if (node instanceof CompositeNode) { - NodeWithCachedOffset firstLeaf = firstLeaf((CompositeNode) node, currentOffset); - if (firstLeaf != null) { - return firstLeaf; - } - } - CompositeNode parent = node.getParent(); - EList siblings = parent.getChildren(); - int childIndex = siblings.indexOf(node); - while (++childIndex < siblings.size()) { - AbstractNode sibling = siblings.get(childIndex); - if (sibling instanceof LeafNode) { - if (!((LeafNode) sibling).isHidden()) { - return new NodeWithCachedOffset(currentOffset, sibling); - } - currentOffset += sibling.length(); - } - else if (sibling instanceof CompositeNode) { - return nextUnhiddenLeaf(sibling, currentOffset); - } - } - return nextUnhiddenLeaf(parent, currentOffset); - } - - private static NodeWithCachedOffset firstLeaf(CompositeNode node, int currentOffset) { - EList children = node.getChildren(); - for (AbstractNode child : children) { - if (child instanceof LeafNode) { - if (!((LeafNode) child).isHidden()) { - return new NodeWithCachedOffset(currentOffset, child); - } - currentOffset += child.length(); - } - else if (child instanceof CompositeNode) { - NodeWithCachedOffset leafFromChild = firstLeaf((CompositeNode) child, currentOffset); - if (leafFromChild != null) { - return leafFromChild; - } - } - } - return null; - } - - private static NodeWithCachedOffset previousUnhiddenLeaf(AbstractNode node, int currentOffset) { - CompositeNode parent = node.getParent(); - EList siblings = parent.getChildren(); - int childIndex = siblings.indexOf(node); - while (--childIndex >= 0) { - AbstractNode sibling = siblings.get(childIndex); - if (sibling instanceof LeafNode) { - currentOffset -= sibling.length(); - if(!((LeafNode) sibling).isHidden()) { - return new NodeWithCachedOffset(currentOffset, sibling); - } - } - else { - NodeWithCachedOffset leafFromComposite = lastUnhiddenLeaf((CompositeNode) sibling, currentOffset); - if (leafFromComposite != null) { - return leafFromComposite; - } - } - } - return previousUnhiddenLeaf(parent, currentOffset); - } - - private static NodeWithCachedOffset lastUnhiddenLeaf(CompositeNode node, int currentOffset) { - EList children = node.getChildren(); - for (int i = children.size() - 1; i >= 0; --i) { - AbstractNode child = children.get(i); - if (child instanceof LeafNode) { - currentOffset -= child.length(); - if(!((LeafNode) child).isHidden()) { - return new NodeWithCachedOffset(currentOffset, child); - } - } - else if (child instanceof CompositeNode) { - NodeWithCachedOffset leafFromChild = lastUnhiddenLeaf((CompositeNode) child, currentOffset); - if (leafFromChild != null) { - return leafFromChild; - } - } - } - return null; - } -} +} \ No newline at end of file diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/NodeContentAdapter.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/NodeContentAdapter.java new file mode 100644 index 000000000..507fcf4fd --- /dev/null +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/NodeContentAdapter.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2008 itemis AG (http://www.itemis.eu) 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.parsetree; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EContentAdapter; + +/** + * @author Jan Köhnlein - Initial contribution and API + * + */ +public class NodeContentAdapter extends EContentAdapter { + + @Override + public void notifyChanged(Notification notification) { + super.notifyChanged(notification); + Object notifier = notification.getNotifier(); + if (notifier instanceof CompositeNode) { + CompositeNode parent = (CompositeNode) notifier; + Object feature = notification.getFeature(); + if (ParsetreePackage.Literals.COMPOSITE_NODE__CHILDREN.equals(feature)) { + AbstractNode child = (AbstractNode) notification.getNewValue(); + int eventType = notification.getEventType(); + int position = notification.getPosition(); + switch (eventType) { + case Notification.ADD: + if (position == 0) { + updateOffsetAndLine(child, new NodeInfo(parent.getOffset(), parent.getLine())); + } + else { + AbstractNode predecessor = parent.getChildren().get(position - 1); + updateOffsetAndLine(child, new NodeInfo((predecessor.getOffset() + predecessor.length()), predecessor.endLine())); + } + break; + case Notification.REMOVE: + if (position == 0) { + updateOffsetAndLine(parent, new NodeInfo(parent.getOffset(), parent.getLine())); + } + else { + AbstractNode successor = parent.getChildren().get(position); + updateOffsetAndLine(successor, new NodeInfo(child.getOffset(), child.getLine())); + } + break; + case Notification.ADD_MANY: + case Notification.MOVE: + case Notification.REMOVE_MANY: + updateOffsetAndLine(parent, new NodeInfo(parent.getOffset(), parent.getLine())); + break; + default: + break; + } + } + } + } + + @Override + protected void setTarget(EObject target) { + if (target instanceof AbstractNode) { + AbstractNode targetNode = (AbstractNode) target; + CompositeNode parent = targetNode.getParent(); + if (parent != null) { + EList siblings = parent.getChildren(); + int index = siblings.indexOf(target); + if (index == 0) { + updateOffsetAndLine(targetNode, new NodeInfo(parent.getOffset(), parent.getLine())); + } + else { + AbstractNode predecessor = siblings.get(index - 1); + updateOffsetAndLine(targetNode, new NodeInfo((predecessor.getOffset() + predecessor.length()), predecessor.endLine())); + } + } + else { + updateOffsetAndLine(targetNode, new NodeInfo(0, 1)); + } + } + } + + static class NodeInfo { + int offset; + int line; + + public NodeInfo(int offset, int line) { + this.offset = offset; + this.line = line; + } + } + + protected NodeInfo updateOffsetAndLineInContents(AbstractNode node, NodeInfo info) { + node.setOffset(info.offset); + node.setLine(info.line); + if (node instanceof LeafNode) { + info.offset += node.length(); + info.line = node.endLine(); + } + if (node instanceof CompositeNode) { + for (AbstractNode child : ((CompositeNode) node).getChildren()) { + info = updateOffsetAndLineInContents(child, info); + } + } + return info; + } + + protected AbstractNode updateOffsetAndLine(AbstractNode node, NodeInfo info) { + updateOffsetAndLineInContents(node, info); + CompositeNode parent = node.getParent(); + if (parent != null) { + EList siblings = parent.getChildren(); + int index = siblings.indexOf(node); + for (int i = index + 1; i < siblings.size(); ++i) { + info = updateOffsetAndLineInContents(siblings.get(i), info); + } + } + return node; + } +} diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/NodeUtil.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/NodeUtil.java index 18e5a1fc6..f34fc0ae3 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/NodeUtil.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/NodeUtil.java @@ -101,8 +101,13 @@ public class NodeUtil { name = grammarElement.getClass().getSimpleName(); } String astElementAsString = (node.getElement() == null) ? "null" : node.getElement().eClass().getName(); - System.out.println(indent + node.getLookahead() + " " + node.getLookaheadConsumed() + " " + name + " : " + node.serialize() - + " -> " + astElementAsString); + System.out.print(indent + name + " : " + node.serialize() + + " -> " + astElementAsString + " la={ "); + for (LeafNode lookaheadNode : node.getLookaheadLeafNodes()) { + System.out.print("\""+ lookaheadNode.getText() +"\" "); + } + System.out.print(" (" + node.getOffset() + ", " + node.length() + ")"); + System.out.println("}"); } } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/impl/ParsetreeUtil.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/impl/ParsetreeUtil.java index 02529c4a9..f4a7267c2 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/impl/ParsetreeUtil.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/parsetree/impl/ParsetreeUtil.java @@ -41,20 +41,6 @@ public class ParsetreeUtil { + abstractParserNode.eClass().getName()); } - public static int offset(AbstractNodeImpl abstractParserNode) { - checkArgument(abstractParserNode); - AbstractNode rootContainer = (AbstractNode) EcoreUtil.getRootContainer(abstractParserNode); - if (rootContainer == abstractParserNode) { - return 0; - } - EList leafNodes = rootContainer.getLeafNodes(abstractParserNode); - int offset = 0; - for (LeafNode leafNode : leafNodes) { - offset += leafNode.length(); - } - return offset; - } - private static void checkArgument(AbstractNodeImpl abstractParserNode) { int classifierID = abstractParserNode.eClass().getClassifierID(); if (classifierID != ParsetreePackage.COMPOSITE_NODE && classifierID != ParsetreePackage.LEAF_NODE) { @@ -79,6 +65,18 @@ public class ParsetreeUtil { } return line; } + + public static int endLine(AbstractNodeImpl _this) { + int line = _this.getLine(); + String text = _this.serialize(); + char[] charArray = text.toCharArray(); + for (char c : charArray) { + // TODO handle os specific newlines + if (c == '\n' || c == '\r') + line++; + } + return line; + } public static String serialize(AbstractNodeImpl _this) { checkArgument(_this); diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java index 66fdea79c..39291f4bc 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java @@ -25,6 +25,7 @@ import org.eclipse.xtext.parsetree.AbstractNode; import org.eclipse.xtext.parsetree.CompositeNode; import org.eclipse.xtext.parsetree.IParseTreeConstructor; import org.eclipse.xtext.parsetree.NodeAdapter; +import org.eclipse.xtext.parsetree.NodeContentAdapter; import org.eclipse.xtext.service.Inject; /** @@ -58,6 +59,13 @@ public class XtextResource extends ResourceImpl { int documentGrowth = length - rootNode.length(); int originalLength = length - documentGrowth; parseResult = parser.reparse(rootNode, offset, originalLength, change); + if (parseResult != null && parseResult.getRootNode() != rootNode) { + addNodeContentAdapter(); + } + } + + private void addNodeContentAdapter() { + parseResult.getRootNode().eAdapters().add(new NodeContentAdapter()); } @Override @@ -69,6 +77,7 @@ public class XtextResource extends ResourceImpl { if (rootElement != null) { getContents().add(rootElement); } + addNodeContentAdapter(); } } diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parseerrorhandling/ParseErrorHandlingTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parseerrorhandling/ParseErrorHandlingTest.java index e785ae71f..ce6cfd326 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parseerrorhandling/ParseErrorHandlingTest.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parseerrorhandling/ParseErrorHandlingTest.java @@ -31,8 +31,8 @@ public class ParseErrorHandlingTest extends AbstractGeneratorTest { EList errors = NodeUtil.getRootNode(root).allSyntaxErrors(); assertEquals(1,errors.size()); assertEquals("%", ((LeafNode)errors.get(0).getNode()).getText()); - assertEquals(1, errors.get(0).getNode().line()); - assertEquals(15, errors.get(0).getNode().offset()); + assertEquals(1, errors.get(0).getNode().getLine()); + assertEquals(15, errors.get(0).getNode().getOffset()); assertEquals(1, errors.get(0).getNode().length()); assertEquals(1, errors.size()); } @@ -41,8 +41,8 @@ public class ParseErrorHandlingTest extends AbstractGeneratorTest { EObject root = getModel("import 'holla' foo returns x::y::Z : name=ID;"); EList errors = NodeUtil.getRootNode(root).allSyntaxErrors(); assertEquals("::", ((LeafNode)errors.get(0).getNode()).getText()); - assertEquals(1, errors.get(0).getNode().line()); - assertEquals(31, errors.get(0).getNode().offset()); + assertEquals(1, errors.get(0).getNode().getLine()); + assertEquals(31, errors.get(0).getNode().getOffset()); assertEquals(2, errors.get(0).getNode().length()); assertEquals(1, errors.size()); } diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/AbstractPartialParserTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/AbstractPartialParserTest.java index ecf73f426..af09b7550 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/AbstractPartialParserTest.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/AbstractPartialParserTest.java @@ -19,7 +19,7 @@ import org.eclipse.xtext.util.EmfStructureComparator; */ public abstract class AbstractPartialParserTest extends AbstractGeneratorTest { - protected static final boolean DEBUG = false; + protected static final boolean DEBUG = true; protected EmfStructureComparator comparator; @Override diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/LookaheadTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/LookaheadTest.java deleted file mode 100644 index c65e3ff6c..000000000 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/LookaheadTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 itemis AG (http://www.itemis.eu) 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.parser; - -import static org.eclipse.xtext.parsetree.NodeUtil.dumpCompositeNodes; -import static org.eclipse.xtext.parsetree.NodeUtil.getCompositeChildren; - -import java.util.List; - -import org.eclipse.xtext.parsetree.CompositeNode; -import org.eclipse.xtext.testlanguages.LookaheadLanguageStandaloneSetup; -import org.eclipse.xtext.tests.AbstractGeneratorTest; - -/** - * @author Jan Köhnlein - Initial contribution and API - * - */ -public class LookaheadTest extends AbstractGeneratorTest { - - /* (non-Javadoc) - * @see org.eclipse.xtext.tests.AbstractGeneratorTest#setUp() - */ - @Override - protected void setUp() throws Exception { - super.setUp(); - with(LookaheadLanguageStandaloneSetup.class); - } - - public void testLookahead() throws Exception { - CompositeNode rootNode = getRootNode("bar a foo bar c b d foo bar b c"); - dumpCompositeNodes("", rootNode); - assertEquals(0, rootNode.getLookahead()); - List alts = getCompositeChildren(rootNode); - assertEquals(1, alts.get(0).getLookahead()); - assertEquals(1, alts.get(1).getLookahead()); - assertEquals(1, alts.get(2).getLookahead()); - assertEquals(1, getCompositeChildren(alts.get(0)).get(0).getLookahead()); - CompositeNode lookahead0 = getCompositeChildren(alts.get(1)).get(0); - assertEquals(3, lookahead0.getLookahead()); - assertEquals(0, getCompositeChildren(lookahead0).get(0).getLookahead()); - CompositeNode lookahead3 = getCompositeChildren(alts.get(2)).get(0); - assertEquals(3, lookahead3.getLookahead()); - assertEquals(0, getCompositeChildren(lookahead3).get(0).getLookahead()); - } - -} diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/PartialParserReplaceTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/PartialParserReplaceTest.java index fec2ffd8e..b17dbe015 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/PartialParserReplaceTest.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/PartialParserReplaceTest.java @@ -25,9 +25,9 @@ public class PartialParserReplaceTest extends AbstractPartialParserTest { public void testExpression() throws Exception { with(SimpleExpressionsStandaloneSetup.class); String model = "(a+b+c)*(c/d)"; - replaceAndReparse(model, 2, 2, "+hugo+egon", "a+hugo+egon+c"); + replaceAndReparse(model, 2, 2, "+hugo+egon", "(a+hugo+egon+c)"); replaceAndReparse(model, 8, 5, "egon", "egon"); - replaceAndReparse(model, 1, 2, "", "b+c"); + replaceAndReparse(model, 1, 2, "", "(b+c)"); replaceAndReparse(model, 6, 3, "*", "(a+b+c*c/d)"); replaceAndReparse(model, 3, 1, "(x+y+z)", "(x+y+z)"); @@ -40,7 +40,7 @@ public class PartialParserReplaceTest extends AbstractPartialParserTest { public void testLookahead() throws Exception { with(LookaheadLanguageStandaloneSetup.class); String model = "foo bar b c"; - replaceAndReparse(model, 10, 1, "d", " d"); + replaceAndReparse(model, 10, 1, "d", "foo bar b d"); replaceAndReparse(model, 8, 1, "b", "foo bar b c"); replaceAndReparse(model, 0, model.length(), "", ""); } diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/PartialParsingPerformanceTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/PartialParsingPerformanceTest.java index 60b400a3d..945af90d4 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/PartialParsingPerformanceTest.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parser/PartialParsingPerformanceTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others. + * Copyright (c) NUM_ELEMENTS8 itemis AG (http://www.itemis.eu) 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 @@ -18,15 +18,15 @@ import org.eclipse.xtext.testlanguages.SimpleExpressionsStandaloneSetup; */ public class PartialParsingPerformanceTest extends AbstractPartialParserTest { - public void testPerformance() throws Exception { - int magicnumber = 10; + private static final int NUM_ELEMENTS = 10; + public void testExpression() throws Exception { with(SimpleExpressionsStandaloneSetup.class); StringBuffer modelBuffer = new StringBuffer(); - for(int i=0; i) astParentElement.eGet(containmentFeature)).contains(parsingPointers.findASTReplaceElement())); - } else { + if (astParentElement != null) { + EStructuralFeature containmentFeature = astParentElement.eClass().getEStructuralFeature( + containmentFeatureName); + if (containmentFeature.isMany()) { + assertTrue(((List) astParentElement.eGet(containmentFeature)).contains(parsingPointers + .findASTReplaceElement())); + } + else { assertTrue(astParentElement.eGet(containmentFeature).equals(parsingPointers.findASTReplaceElement())); } } diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/LengthOffsetLineTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/LengthOffsetLineTest.java index 35db938fd..2b8b45dfd 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/LengthOffsetLineTest.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/LengthOffsetLineTest.java @@ -21,23 +21,23 @@ public class LengthOffsetLineTest extends AbstractGeneratorTest { CompositeNode node = (CompositeNode) getRootNode(model); EList leafNodes = node.getLeafNodes(); Iterator iter = leafNodes.iterator(); - assertEquals(0,iter.next().offset()); - assertEquals(7,iter.next().offset()); - assertEquals(8,iter.next().offset()); - assertEquals(11,iter.next().offset()); - assertEquals(12,iter.next().offset()); - assertEquals(13,iter.next().offset()); - assertEquals(20,iter.next().offset()); - assertEquals(21,iter.next().offset()); - assertEquals(24,iter.next().offset()); + assertEquals(0,iter.next().getOffset()); + assertEquals(7,iter.next().getOffset()); + assertEquals(8,iter.next().getOffset()); + assertEquals(11,iter.next().getOffset()); + assertEquals(12,iter.next().getOffset()); + assertEquals(13,iter.next().getOffset()); + assertEquals(20,iter.next().getOffset()); + assertEquals(21,iter.next().getOffset()); + assertEquals(24,iter.next().getOffset()); } public void testOffset2() throws Exception { String model = "element foo;\nelement bar;"; CompositeNode node = (CompositeNode) getRootNode(model); Iterator iter = node.getChildren().iterator(); - assertEquals(0,iter.next().offset()); - assertEquals(12,iter.next().offset()); + assertEquals(0,iter.next().getOffset()); + assertEquals(12,iter.next().getOffset()); assertFalse(iter.hasNext()); } @@ -46,15 +46,15 @@ public class LengthOffsetLineTest extends AbstractGeneratorTest { CompositeNode node = (CompositeNode) getRootNode(model); EList leafNodes = node.getLeafNodes(); Iterator iter = leafNodes.iterator(); - assertEquals(1,iter.next().line()); - assertEquals(1,iter.next().line()); - assertEquals(1,iter.next().line()); - assertEquals(1,iter.next().line()); - assertEquals(1,iter.next().line()); - assertEquals(2,iter.next().line()); - assertEquals(2,iter.next().line()); - assertEquals(2,iter.next().line()); - assertEquals(2,iter.next().line()); + assertEquals(1,iter.next().getLine()); + assertEquals(1,iter.next().getLine()); + assertEquals(1,iter.next().getLine()); + assertEquals(1,iter.next().getLine()); + assertEquals(1,iter.next().getLine()); + assertEquals(2,iter.next().getLine()); + assertEquals(2,iter.next().getLine()); + assertEquals(2,iter.next().getLine()); + assertEquals(2,iter.next().getLine()); assertFalse(iter.hasNext()); } @@ -62,12 +62,12 @@ public class LengthOffsetLineTest extends AbstractGeneratorTest { String model = "element foo;\nelement bar;\nelement bar;\nelement bar;"; CompositeNode node = (CompositeNode) getRootNode(model); Iterator iter = node.getChildren().iterator(); - assertEquals(1,iter.next().line()); + assertEquals(1,iter.next().getLine()); //Note: because preceding whitespace is added to the following node, // the '\n' is always added to the following composite node - assertEquals(1,iter.next().line()); - assertEquals(2,iter.next().line()); - assertEquals(3,iter.next().line()); + assertEquals(1,iter.next().getLine()); + assertEquals(2,iter.next().getLine()); + assertEquals(3,iter.next().getLine()); assertFalse(iter.hasNext()); } @@ -80,7 +80,7 @@ public class LengthOffsetLineTest extends AbstractGeneratorTest { assertEquals(5,nodes.size()); int offset = 0; for (LeafNode leafNode : nodes) { - assertEquals(offset,leafNode.offset()); + assertEquals(offset,leafNode.getOffset()); offset += leafNode.length(); } } diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/NodeContentAdapterTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/NodeContentAdapterTest.java new file mode 100644 index 000000000..f34403083 --- /dev/null +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/NodeContentAdapterTest.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2008 itemis AG (http://www.itemis.eu) 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.parsetree; + +import org.eclipse.xtext.testlanguages.ReferenceGrammarStandaloneSetup; +import org.eclipse.xtext.tests.AbstractGeneratorTest; + +/** + * @author Jan Köhnlein - Initial contribution and API + * + */ +public class NodeContentAdapterTest extends AbstractGeneratorTest{ + + public void testNodeContentAdapter() throws Exception { + with(ReferenceGrammarStandaloneSetup.class); + CompositeNode rootNode = getRootNode("spielplatz 112 'Jajaja' { kind ( Dennis 7) }"); + NodeUtil.dumpCompositeNodes("", rootNode); + } +} diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/reconstr/ComplexReconstrTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/reconstr/ComplexReconstrTest.java index cffffae55..9baf83328 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/reconstr/ComplexReconstrTest.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/parsetree/reconstr/ComplexReconstrTest.java @@ -9,8 +9,6 @@ package org.eclipse.xtext.parsetree.reconstr; import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.RuleCall; -import org.eclipse.xtext.parsetree.CompositeNode; import org.eclipse.xtext.parsetree.IParseTreeConstructor; import org.eclipse.xtext.parsetree.NodeUtil; import org.eclipse.xtext.tests.AbstractGeneratorTest; diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/reference/LeafNodeBug_234132.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/reference/LeafNodeBug_234132.java index cc749a55e..61b52991c 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/reference/LeafNodeBug_234132.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/reference/LeafNodeBug_234132.java @@ -30,9 +30,9 @@ public class LeafNodeBug_234132 extends AbstractGeneratorTest { System.out.println("Model length=" + model.length()); for (LeafNode leafNode : leafNodes) { String text = leafNode.getText(); - System.out.println("Leaf node" + leafNode.toString() + " offset=" + leafNode.offset() + " length=" + leafNode.length() + " text=" + ((text != null)? text : "")); - assertTrue(leafNode.length() + leafNode.offset() <= model.length()); - assertEquals(model.substring(leafNode.offset(), leafNode.offset() + leafNode.length()), leafNode.getText()); + System.out.println("Leaf node" + leafNode.toString() + " offset=" + leafNode.getOffset() + " length=" + leafNode.length() + " text=" + ((text != null)? text : "")); + assertTrue(leafNode.length() + leafNode.getOffset() <= model.length()); + assertEquals(model.substring(leafNode.getOffset(), leafNode.getOffset() + leafNode.length()), leafNode.getText()); } } }