protected EObject getOldSemanticElement(ICompositeNode replaceMe, PartialParsingPointers parsingPointers) { EObject oldSemanticElement = null; if (replaceMe.hasDirectSemanticElement()) { oldSemanticElement = replaceMe.getSemanticElement(); } else { List<ICompositeNode> nodesEnclosingRegion = parsingPointers.getNodesEnclosingRegion(); for (int i = nodesEnclosingRegion.size() - 1; i >= 0; --i) { ICompositeNode enclosingNode = nodesEnclosingRegion.get(i); if (enclosingNode == replaceMe) { break; } if (enclosingNode.hasDirectSemanticElement()) oldSemanticElement = enclosingNode.getSemanticElement(); } } return oldSemanticElement; }
protected PartialParsingPointers calculatePartialParsingPointers(ICompositeNode oldRoot, ILeafNode left, ILeafNode right) { ICompositeNode result = right.getParent(); while(result.getTotalOffset() > left.getTotalOffset()) { result = result.getParent(); } List<ICompositeNode> nodesEnclosingRegion = getAllParents(result); Range range = new Range(left.getTotalOffset(), right.getTotalEndOffset()); List<ICompositeNode> validReplaceRootNodes = internalFindValidReplaceRootNodeForChangeRegion(nodesEnclosingRegion); filterInvalidRootNodes(validReplaceRootNodes); if (validReplaceRootNodes.isEmpty()) { validReplaceRootNodes = Collections.singletonList(oldRoot); } return new PartialParsingPointers(oldRoot, range.getOffset(), range.getLength(), validReplaceRootNodes, nodesEnclosingRegion); }
protected void checkParseRegionPointers( PartialParsingPointers parsingPointers, String expectedRegion, String expectedGrammarElementClassName, String expectedEntryRuleName) { assertEquals(expectedRegion, getReparseRegion(parsingPointers)); EObject grammarElement = parsingPointers.getDefaultReplaceRootNode().getGrammarElement(); String grammarElementName = grammarElement.eClass().getName(); assertEquals(expectedGrammarElementClassName, grammarElementName); EObject ruleOrRuleCall = parsingPointers.findEntryRuleOrRuleCall(parsingPointers.getDefaultReplaceRootNode()); if (ruleOrRuleCall instanceof RuleCall) { ruleOrRuleCall = ((RuleCall) ruleOrRuleCall).getRule(); } assertEquals(expectedEntryRuleName, ((AbstractRule) ruleOrRuleCall).getName()); }
protected void replaceAndReparse(String model, int offset, int length, String change, String expectedReparseRegion) throws Exception { IParseResult parseResult = getParseResult(model); PartialParsingPointers parsingPointers = getPartialParser().calculatePartialParsingPointers(parseResult, offset, length); String reparseRegion = getPartialParser().insertChangeIntoReplaceRegion(parsingPointers .getDefaultReplaceRootNode(), new ReplaceRegion(offset, length, change)); assertEquals(expectedReparseRegion, reparseRegion); final Wrapper<Boolean> unloaded = Wrapper.wrap(Boolean.FALSE); getPartialParser().setUnloader(new IReferableElementsUnloader() { @Override public void unloadRoot(EObject root) { unloaded.set(Boolean.TRUE); } }); IParseResult partiallyReparse = reparse(parseResult, offset, length, change); assertTrue("unloaded", unloaded.get()); assertFalse(partiallyReparse.getRootNode().getText(), partiallyReparse.hasSyntaxErrors()); String expectedReparseModel = model.substring(0, offset) + change + model.substring(offset + length); assertEquals(expectedReparseModel, partiallyReparse.getRootNode().getText()); }
protected void replaceAndReparse(String model, int offset, int length, String change, String expectedReparseRegion) throws Exception { IParseResult parseResult = getParseResultAndExpect(model, UNKNOWN_EXPECTATION); PartialParsingPointers parsingPointers = getPartialParser().calculatePartialParsingPointers(parseResult, offset, length); String reparseRegion = getPartialParser().insertChangeIntoReplaceRegion(parsingPointers .getDefaultReplaceRootNode(), new ReplaceRegion(offset, length, change)); assertEquals(expectedReparseRegion, reparseRegion); final Wrapper<Boolean> unloaded = Wrapper.wrap(Boolean.FALSE); getPartialParser().setUnloader(new IReferableElementsUnloader() { @Override public void unloadRoot(EObject root) { unloaded.set(Boolean.TRUE); } }); IParseResult partiallyReparse = reparse(parseResult, offset, length, change); assertTrue("unloaded", unloaded.get()); String expectedReparseModel = model.substring(0, offset) + change + model.substring(offset + length); assertEquals(expectedReparseModel, partiallyReparse.getRootNode().getText()); compareWithFullParse(model, offset, length, change); }
public PartialParsingPointers calculatePartialParsingPointers(final IParseResult previousParseResult, final int offset, final int replacedTextLength) { int myOffset = offset; int myReplacedTextLength = replacedTextLength; ICompositeNode oldRootNode = previousParseResult.getRootNode(); if (myOffset == oldRootNode.getTotalLength() && myOffset != 0) { // newText is appended, so look for the last original character instead --myOffset; myReplacedTextLength = 1; } // include any existing parse errors Range range = new Range(myOffset, myReplacedTextLength + myOffset); if (previousParseResult.hasSyntaxErrors()) { range.mergeAllSyntaxErrors(oldRootNode); } myOffset = range.getOffset(); List<ICompositeNode> nodesEnclosingRegion = collectNodesEnclosingChangeRegion(oldRootNode, range); List<ICompositeNode> validReplaceRootNodes = internalFindValidReplaceRootNodeForChangeRegion(nodesEnclosingRegion, range); filterInvalidRootNodes(oldRootNode, validReplaceRootNodes); if (validReplaceRootNodes.isEmpty()) { validReplaceRootNodes = Collections.singletonList(oldRootNode); } return new PartialParsingPointers(oldRootNode, myOffset, myReplacedTextLength, validReplaceRootNodes, nodesEnclosingRegion); }
protected ICompositeNode getReplacedNode(PartialParsingPointers parsingPointers) { List<ICompositeNode> validReplaceRootNodes = parsingPointers.getValidReplaceRootNodes(); ICompositeNode replaceMe = null; for (int i = validReplaceRootNodes.size() - 1; i >= 0; --i) { replaceMe = validReplaceRootNodes.get(i); if (!(replaceMe instanceof SyntheticCompositeNode)) { break; } } return replaceMe; }
protected IParseResult doParseRegion(IParser parser, PartialParsingPointers parsingPointers, ICompositeNode replaceMe, String reparseRegion) { EObject entryRuleOrRuleCall = parsingPointers.findEntryRuleOrRuleCall(replaceMe); IParseResult newParseResult = null; try { if (entryRuleOrRuleCall instanceof RuleCall) newParseResult = parser.parse((RuleCall)entryRuleOrRuleCall, new StringReader(reparseRegion), replaceMe.getLookAhead()); else newParseResult = parser.parse((ParserRule)entryRuleOrRuleCall, new StringReader(reparseRegion)); } catch (ParseException exc) { } return newParseResult; }
@Test public void testLookahead_0_2() throws Exception { String model = "bar a foo bar c b d foo bar b c"; for (int i = 0; i < 3; ++i) { PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, i, 1); checkParseRegionPointers(parsingPointers, model, "ParserRule", "Entry"); } }
@Test public void testLookahead_3_4() throws Exception { String model = "bar a foo bar c b d foo bar b c"; for (int i = 3; i < 5; ++i) { PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, i, 1); checkParseRegionPointers(parsingPointers, "bar a", "RuleCall", "LookAhead0"); } }
@Test public void testLookahead_6_8() throws Exception { String model = "bar a foo bar c b d foo bar b c"; for (int i = 6; i < 9; ++i) { PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, i, 1); checkParseRegionPointers(parsingPointers, model, "ParserRule", "Entry"); } }
@Test public void testLookahead_9_14() throws Exception { String model = "bar a foo bar c b d foo bar b c"; for (int i = 9; i < 15; ++i) { PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, i, 1); // actual expecation would lead to yet more complexity in partial parser // checkParseRegionPointers(parsingPointers, " foo bar c b d", "RuleCall", "Alts"); checkParseRegionPointers(parsingPointers, model, "ParserRule", "Entry"); } }
@Test public void testLookahead_15_18() throws Exception { String model = "bar a foo bar c b d foo bar b c"; for (int i = 15; i < 19; ++i) { PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, i, 1); checkParseRegionPointers(parsingPointers, " foo bar c b d", "RuleCall", "LookAhead1"); } }
@Test public void testLookahead_19_22() throws Exception { String model = "bar a foo bar c b d foo bar b c"; for (int i = 19; i < 22; ++i) { PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, i, 1); checkParseRegionPointers(parsingPointers, model, "ParserRule", "Entry"); } }
@Test public void testLookahead_23_28() throws Exception { String model = "bar a foo bar c b d foo bar b c"; for (int i = 23; i < 29; ++i) { PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, i, 1); checkParseRegionPointers(parsingPointers, model, "ParserRule", "Entry"); } }
@Test public void testLookahead_29() throws Exception { String model = "bar a foo bar c b d foo bar b c"; for (int i = 29; i < model.length(); ++i) { PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, i, 1); checkParseRegionPointers(parsingPointers, " c", "RuleCall", "LookAhead4"); } }
protected PartialParsingPointers calculatePartialParsingPointers(String model, int changeRegionStart, int changeRegionSize) throws Exception { IParseResult parseResult = getParseResult(model); PartialParsingPointers partialParsingPointers = getPartialParser().calculatePartialParsingPointers(parseResult, changeRegionStart, changeRegionSize); return partialParsingPointers; }
@Test public void testExpression_9_2() throws Exception { String model = "(a+b+c)*(c/d)"; PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, 9, 2); // actual minimal replace region is c/d but this would lead to accidental complexity // in the partial parser implementation // checkParseRegionPointers(parsingPointers, "c/d", "RuleCall", "Addition"); checkParseRegionPointers(parsingPointers, "(c/d)", "RuleCall", "Parens"); }
@Override public IParseResult reparse(IParser parser, IParseResult previousParseResult, ReplaceRegion changedRegion) { if (isBrokenPreviousState(previousParseResult, changedRegion.getOffset())) { return fullyReparse(parser, previousParseResult, changedRegion); } ICompositeNode oldRootNode = previousParseResult.getRootNode(); Iterator<ILeafNode> leafNodes = oldRootNode.getLeafNodes().iterator(); ILeafNode leftNode = getLeftNode(leafNodes, changedRegion.getOffset()); if (leftNode == null) { return fullyReparse(parser, previousParseResult, changedRegion); } ILeafNode rightNode = getRightNode(leafNodes, changedRegion.getEndOffset()); if (rightNode == null) { return fullyReparse(parser, previousParseResult, changedRegion); } while(leafNodes.hasNext()) { if (leafNodes.next().getSyntaxErrorMessage() != null) { return fullyReparse(parser, previousParseResult, changedRegion); } } String originalText = oldRootNode.getText().substring(leftNode.getTotalOffset()); StringBuilder newTextBuilder = new StringBuilder(originalText); changedRegion.shiftBy(-leftNode.getTotalOffset()).applyTo(newTextBuilder); String newText = newTextBuilder.toString(); if (originalText.equals(newText)) { // nothing to do return previousParseResult; } int originalLength = rightNode.getTotalEndOffset() - leftNode.getTotalOffset(); int expectedLength = originalLength - changedRegion.getLength() + changedRegion.getText().length(); if (!isSameTokenSequence(originalText.substring(0, originalLength), newText, expectedLength)) { // different token sequence, cannot perform a partial parse run return fullyReparse(parser, previousParseResult, changedRegion); } PartialParsingPointers parsingPointers = calculatePartialParsingPointers(oldRootNode, leftNode, rightNode); ICompositeNode replaceMe = getReplacedNode(parsingPointers); if (replaceMe == null || replaceMe == oldRootNode || replaceMe.getOffset() == 0 && replaceMe.getEndOffset() == oldRootNode.getLength()) { return fullyReparse(parser, previousParseResult, changedRegion); } String reparseRegion = insertChangeIntoReplaceRegion(replaceMe, changedRegion); EObject oldSemanticElement = getOldSemanticElement(replaceMe, parsingPointers); if (oldSemanticElement == null) return fullyReparse(parser, previousParseResult, changedRegion); if (oldSemanticElement == replaceMe.getParent().getSemanticElement()) { throw new IllegalStateException("oldParent == oldElement"); } IParseResult newParseResult = doParseRegion(parser, parsingPointers, replaceMe, reparseRegion); if (newParseResult == null) { throw new IllegalStateException("Could not perform a partial parse operation"); } replaceOldSemanticElement(oldSemanticElement, previousParseResult, newParseResult); nodeModelBuilder.replaceAndTransferLookAhead(replaceMe, newParseResult.getRootNode()); ((ParseResult) newParseResult).setRootNode(oldRootNode); StringBuilder builder = new StringBuilder(oldRootNode.getText()); changedRegion.applyTo(builder); nodeModelBuilder.setCompleteContent(oldRootNode, builder.toString()); return newParseResult; }
@Test public void testReference() throws Exception { String model = "spielplatz 17 { kind ( Dennis 6 ) kind ( Sven 7 ) }"; PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, model.indexOf("Sven"), 4); checkParseRegionPointers(parsingPointers, " kind ( Sven 7 )", "RuleCall", "Kind"); }
@Test public void testExpression_1_1() throws Exception { String model = "(a+b+c)*(c/d)"; PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, 1, 1); checkParseRegionPointers(parsingPointers, "(a+b+c)", "RuleCall", "Parens"); }
@Test public void testExpression_3_1() throws Exception { String model = "(a+b+c)*(c/d)"; PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, 3, 1); checkParseRegionPointers(parsingPointers, "(a+b+c)", "RuleCall", "Parens"); }
@Test public void testExpression_5_2() throws Exception { String model = "(a+b+c)*(c/d)"; PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, 5, 2); checkParseRegionPointers(parsingPointers, "(a+b+c)", "RuleCall", "Parens"); }
@Test public void testExpression_6_1() throws Exception { String model = "(a+b+c)*(c/d)"; PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, 6, 1); checkParseRegionPointers(parsingPointers, "(a+b+c)", "RuleCall", "Parens"); }
@Test public void testExpression_8_2() throws Exception { String model = "(a+b+c)*(c/d)"; PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, 8, 2); checkParseRegionPointers(parsingPointers, "(a+b+c)*(c/d)", "ParserRule", "Sequence"); }
@Test public void testExpression_a_b() throws Exception { String model = "a b"; PartialParsingPointers parsingPointers = calculatePartialParsingPointers(model, 1, 1); checkParseRegionPointers(parsingPointers, "a b", "Action", "Sequence"); }
protected String getReparseRegion(PartialParsingPointers parsingPointers) { ICompositeNode replaceRootNode = parsingPointers.getDefaultReplaceRootNode(); return replaceRootNode.getText(); }