[formatter] fix ITextRegionAccess#getInvokingGrammarElement(EObject)

Make sure this method returns the same grammar element, no matter
whether the text region access has been constructid via 
serializer or node model.

Signed-off-by: Moritz Eysholdt <moritz.eysholdt@itemis.de>
This commit is contained in:
Moritz Eysholdt 2015-04-20 15:39:49 +02:00
parent 794ac2268e
commit 0025d38d88
13 changed files with 271 additions and 197 deletions

View file

@ -155,7 +155,9 @@ public class FormatterTester {
if (req.isUseNodeModel() && useSerializer) {
ITextRegionAccess nmRegions = createRegionAccessViaNodeModel(resource);
ITextRegionAccess serRegions = createRegionAccessViaSerializer(resource);
Assert.assertEquals(toString(nmRegions), toString(serRegions));
String nmString = toString(nmRegions);
String serString = toString(serRegions);
Assert.assertEquals(nmString, serString);
return nmRegions;
} else if (req.isUseNodeModel()) {
ITextRegionAccess nmRegions = createRegionAccessViaNodeModel(resource);

View file

@ -9,14 +9,17 @@ package org.eclipse.xtext.formatting2.debug;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.formatting2.regionaccess.IAstRegion;
import org.eclipse.xtext.formatting2.regionaccess.IComment;
import org.eclipse.xtext.formatting2.regionaccess.IEObjectRegion;
import org.eclipse.xtext.formatting2.regionaccess.IHiddenRegion;
import org.eclipse.xtext.formatting2.regionaccess.IHiddenRegionPart;
import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion;
@ -30,22 +33,48 @@ import org.eclipse.xtext.util.EmfFormatter;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
public class TextRegionAccessToString {
protected static enum AstRegionComparator implements Comparator<IAstRegion> {
CHILDREN_FIRST {
@Override
public int compare(IAstRegion o1, IAstRegion o2) {
EObject e1 = o1.getSemanticElement();
EObject e2 = o2.getSemanticElement();
if (e1 == e2)
return 0;
if (EcoreUtil.isAncestor(e1, e2))
return 1;
return -1;
}
},
CONTAINER_FIRST {
@Override
public int compare(IAstRegion o1, IAstRegion o2) {
EObject e1 = o1.getSemanticElement();
EObject e2 = o2.getSemanticElement();
if (e1 == e2)
return 0;
if (EcoreUtil.isAncestor(e1, e2))
return -1;
return 1;
}
};
}
private static final int TITLE_WIDTH = 9;
private static final String SEMANTIC_PADDED = Strings.padEnd("Semantic", TITLE_WIDTH, ' ');
private static final String EOBJECT_END_PADDED = Strings.padEnd("End", TITLE_WIDTH, ' ');
private static final String EOBJECT_START_PADDED = Strings.padEnd("Start", TITLE_WIDTH, ' ');
private static final String HIDDEN = "Hidden";
private static final String HIDDEN_PADDED = Strings.padEnd(HIDDEN, TITLE_WIDTH, ' ');
private static final String EOBJECT_START_PADDED = Strings.padEnd("Start", TITLE_WIDTH, ' ');
private static final String EOBJECT_END_PADDED = Strings.padEnd("End", TITLE_WIDTH, ' ');
private static final String SEMANTIC_PADDED = Strings.padEnd("Semantic", TITLE_WIDTH, ' ');
private Function<AbstractElement, String> grammarToString = new GrammarElementTitleSwitch().showRule()
.showAssignments().showQualified();
@ -56,42 +85,6 @@ public class TextRegionAccessToString {
private ITextSegment origin;
protected void collectHiddenRegionsBySemanticObject(List<ITextSegment> regions,
Multimap<IHiddenRegion, EObject> leadingHiddens, Multimap<IHiddenRegion, EObject> trailingHiddens,
List<String> errors) {
Set<EObject> sem = Sets.newHashSet();
for (ITextSegment s : regions)
if (s instanceof ISemanticRegion)
sem.add(((ISemanticRegion) s).getSemanticElement());
ISemanticRegion previous = ((ISequentialRegion) regions.get(0)).getPreviousSemanticRegion();
if (previous != null)
sem.add(previous.getSemanticElement());
ISemanticRegion next = ((ISequentialRegion) regions.get(regions.size() - 1)).getNextSemanticRegion();
if (next != null)
sem.add(next.getSemanticElement());
sem.remove(null);
Set<EObject> containers = Sets.newHashSet();
for (EObject s : sem) {
EObject container = s.eContainer();
while (container != null && containers.add(container))
container = container.eContainer();
}
sem.addAll(containers);
ITextRegionAccess access = regions.get(0).getTextRegionAccess();
for (EObject s : sem) {
IHiddenRegion leading = access.leadingHiddenRegion(s);
if (leading == null)
errors.add("ERROR: " + EmfFormatter.objPath(s) + " has no leading HiddenRegion.");
else
leadingHiddens.put(leading, s);
IHiddenRegion trailing = access.trailingHiddenRegion(s);
if (trailing == null)
errors.add("ERROR: " + EmfFormatter.objPath(s) + " has no trailing HiddenRegion.");
else
trailingHiddens.put(trailing, s);
}
}
public TextRegionAccessToString hideColumnExplanation() {
this.hideColumnExplanation = true;
return this;
@ -122,10 +115,27 @@ public class TextRegionAccessToString {
@Override
public String toString() {
List<ITextSegment> list = toTokenAndGapList();
Multimap<IHiddenRegion, EObject> leadingHiddens = LinkedHashMultimap.create();
Multimap<IHiddenRegion, EObject> trailingHiddens = LinkedHashMultimap.create();
if (list.isEmpty())
return "(empty)";
Multimap<IHiddenRegion, IEObjectRegion> hiddens = LinkedListMultimap.create();
List<String> errors = Lists.newArrayList();
collectHiddenRegionsBySemanticObject(list, leadingHiddens, trailingHiddens, errors);
ITextRegionAccess access = list.get(0).getTextRegionAccess();
List<IEObjectRegion> objects = access.regionsForAllEObjects();
for (IEObjectRegion obj : objects) {
IHiddenRegion previous = obj.getPreviousHiddenRegion();
IHiddenRegion next = obj.getNextHiddenRegion();
EObject element = obj.getSemanticElement();
if (previous == null)
errors.add("ERROR: " + EmfFormatter.objPath(element) + " has no leading HiddenRegion.");
else
hiddens.put(previous, obj);
if (previous != next) {
if (next == null)
errors.add("ERROR: " + EmfFormatter.objPath(element) + " has no trailing HiddenRegion.");
else
hiddens.put(next, obj);
}
}
TextRegionListToString result = new TextRegionListToString();
if (!hideColumnExplanation) {
String explanation = "Columns: 1:offset; 2:length; 3:hidden/semantic; 4: text; 5..n:grammar elements or whispace/comments";
@ -134,17 +144,30 @@ public class TextRegionAccessToString {
for (String error : errors)
result.add(error, false);
for (ITextSegment region : list) {
List<IEObjectRegion> previous = Lists.newArrayList();
List<IEObjectRegion> next = Lists.newArrayList();
List<String> middle = Lists.newArrayList(toString(region));
if (region instanceof IHiddenRegion) {
Collection<EObject> collection = trailingHiddens.get((IHiddenRegion) region);
if (!collection.isEmpty())
result.add(EOBJECT_END_PADDED + toString(collection));
}
result.add(region, toString(region));
if (region instanceof IHiddenRegion) {
Collection<EObject> collection = leadingHiddens.get((IHiddenRegion) region);
if (!collection.isEmpty())
result.add(EOBJECT_START_PADDED + toString(collection));
Collection<IEObjectRegion> found = hiddens.get((IHiddenRegion) region);
for (IEObjectRegion obj : found) {
boolean p = obj.getNextHiddenRegion().equals(region);
boolean n = obj.getPreviousHiddenRegion().equals(region);
if (p && n)
middle.add("Semantic " + toString(obj));
else if (p)
previous.add(obj);
else if (n)
next.add(obj);
}
Collections.sort(previous, AstRegionComparator.CHILDREN_FIRST);
Collections.sort(next, AstRegionComparator.CONTAINER_FIRST);
}
for (IEObjectRegion obj : previous)
result.add(EOBJECT_END_PADDED + toString(obj));
result.add(region, Joiner.on(", ").join(middle));
for (IEObjectRegion obj : next)
result.add(EOBJECT_START_PADDED + toString(obj));
}
return result.toString();
}
@ -153,32 +176,6 @@ public class TextRegionAccessToString {
return rule == null ? "null" : rule.getName();
}
protected String toString(Collection<EObject> objs) {
List<String> result = Lists.newArrayList();
for (EObject obj : objs) {
StringBuilder builder = new StringBuilder();
EStructuralFeature containingFeature = obj.eContainingFeature();
if (containingFeature != null) {
builder.append(containingFeature.getName());
if (containingFeature.isMany()) {
int index = ((List<?>) obj.eContainer().eGet(containingFeature)).indexOf(obj);
builder.append("[" + index + "]");
}
builder.append("=");
}
builder.append(obj.eClass().getName());
EStructuralFeature nameFeature = obj.eClass().getEStructuralFeature("name");
if (nameFeature != null) {
Object name = obj.eGet(nameFeature);
if (name != null)
builder.append("'" + name + "'");
}
result.add(builder.toString());
}
Collections.sort(result);
return Joiner.on(", ").join(result);
}
protected String toString(EObject ele) {
if (ele instanceof AbstractElement)
return grammarToString.apply((AbstractElement) ele);
@ -193,6 +190,35 @@ public class TextRegionAccessToString {
return String.format("%s Comment:%s", text, gammar);
}
protected String toString(IEObjectRegion region) {
EObject obj = region.getSemanticElement();
StringBuilder builder = new StringBuilder();
EStructuralFeature containingFeature = obj.eContainingFeature();
if (containingFeature != null) {
builder.append(containingFeature.getName());
if (containingFeature.isMany()) {
int index = ((List<?>) obj.eContainer().eGet(containingFeature)).indexOf(obj);
builder.append("[" + index + "]");
}
builder.append("=");
}
builder.append(obj.eClass().getName());
EStructuralFeature nameFeature = obj.eClass().getEStructuralFeature("name");
if (nameFeature != null) {
Object name = obj.eGet(nameFeature);
if (name != null)
builder.append("'" + name + "'");
}
EObject element = region.getGrammarElement();
if (element instanceof AbstractElement)
builder.append(" via " + grammarToString.apply((AbstractElement) element));
else if (element instanceof AbstractRule)
builder.append(" via " + ((AbstractRule) element).getName());
else
builder.append(": ERROR: EObject has no grammar element.");
return builder.toString();
}
protected String toString(IHiddenRegion gap) {
List<IHiddenRegionPart> whitespaceAndComments = gap.getParts();
List<String> children = Lists.newArrayListWithExpectedSize(whitespaceAndComments.size());
@ -210,7 +236,9 @@ public class TextRegionAccessToString {
protected String toString(ITextSegment region) {
String result;
if (region instanceof ISemanticRegion)
if (region instanceof IEObjectRegion)
result = toString((IEObjectRegion) region);
else if (region instanceof ISemanticRegion)
result = toString((ISemanticRegion) region);
else if (region instanceof IHiddenRegion)
result = toString((IHiddenRegion) region);
@ -268,15 +296,15 @@ public class TextRegionAccessToString {
return result;
}
public TextRegionAccessToString withOrigin(ITextSegment origin) {
this.origin = origin;
return this;
}
public TextRegionAccessToString withRegionAccess(ITextRegionAccess access) {
this.origin = access.regionForRootEObject();
this.hightlightOrigin = false;
return this;
}
public TextRegionAccessToString withOrigin(ITextSegment origin) {
this.origin = origin;
return this;
}
}

View file

@ -192,4 +192,6 @@ public interface ITextRegionAccess {
String textForOffset(int offset, int length);
List<ILineRegion> expandToLines(ITextSegment segment, int leadingLinesToAdd, int trailingLinesToAdd);
List<IEObjectRegion> regionsForAllEObjects();
}

View file

@ -27,8 +27,8 @@ public class TextRegionAccessBuilder {
return this;
}
public ISequenceAcceptor forSequence(EObject root) {
return this.fromSequencer = createTextRegionAccessBuildingSequencer().withRoot(root);
public ISequenceAcceptor forSequence(EObject ctx, EObject root) {
return this.fromSequencer = createTextRegionAccessBuildingSequencer().withRoot(ctx, root);
}
private TextRegionAccessBuildingSequencer createTextRegionAccessBuildingSequencer() {

View file

@ -22,6 +22,7 @@ import com.google.common.collect.Lists;
*/
public abstract class AbstractEObjectRegion extends AbstractTextSegment implements IEObjectRegion {
private final ITextRegionAccess access;
private EObject grammarElement;
private IHiddenRegion nextHidden;
private IHiddenRegion previousHidden;
private EObject semantcElement;
@ -32,6 +33,11 @@ public abstract class AbstractEObjectRegion extends AbstractTextSegment implemen
this.access = access;
}
@Override
public EObject getGrammarElement() {
return grammarElement;
}
public IHiddenRegion getLeadingHiddenRegion() {
return previousHidden;
}
@ -85,6 +91,10 @@ public abstract class AbstractEObjectRegion extends AbstractTextSegment implemen
return nextHidden;
}
protected void setGrammarElement(EObject grammarElement) {
this.grammarElement = grammarElement;
}
protected void setLeadingHiddenRegion(IHiddenRegion leading) {
this.previousHidden = leading;
}

View file

@ -7,11 +7,6 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2.regionaccess.internal;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.INode;
/**
@ -25,25 +20,7 @@ public class NodeEObjectRegion extends AbstractEObjectRegion {
this.node = node;
}
@Override
public AbstractElement getGrammarElement() {
INode current = node;
while (current != null) {
EObject grammarElement = current.getGrammarElement();
if (GrammarUtil.isAssignedEObjectRuleCall(grammarElement))
return (AbstractElement) grammarElement;
if (grammarElement instanceof Action) {
Action action = (Action) grammarElement;
if (action.getFeature() != null)
return (AbstractElement) grammarElement;
else {
EObject grammarElement2 = ((ICompositeNode) current).getFirstChild().getGrammarElement();
if (GrammarUtil.isAssignedEObjectRuleCall(grammarElement2))
return (AbstractElement) grammarElement2;
}
}
current = current.getParent();
}
return null;
public INode getNode() {
return node;
}
}

View file

@ -7,6 +7,7 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2.regionaccess.internal;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EObject;
@ -17,6 +18,7 @@ import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.XtextResource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
@ -77,4 +79,9 @@ public class NodeModelBasedRegionAccess extends AbstractRegionAccess {
return new TextSegment(this, 0, resource.getParseResult().getRootNode().getTotalEndOffset());
}
@Override
public List<IEObjectRegion> regionsForAllEObjects() {
return ImmutableList.<IEObjectRegion> copyOf(eObjectToTokens.values());
}
}

View file

@ -13,6 +13,7 @@ import java.util.Map;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.RuleCall;
@ -146,6 +147,38 @@ public class NodeModelBasedRegionAccessBuilder {
return false;
}
protected EObject findGrammarElement(INode node, EObject obj) {
INode current = node;
String feature = obj.eContainingFeature().getName();
while (current != null) {
EObject grammarElement = current.getGrammarElement();
Assignment assignment = GrammarUtil.containingAssignment(grammarElement);
if (assignment != null && feature.equals(assignment.getFeature()))
return grammarElement;
if (grammarElement instanceof Action) {
Action action = (Action) grammarElement;
if (feature.equals(action.getFeature()))
return grammarElement;
else if (current == node && current instanceof ICompositeNode) {
INode child = ((ICompositeNode) current).getFirstChild();
while (child instanceof ICompositeNode) {
EObject grammarElement2 = child.getGrammarElement();
Assignment assignment2 = GrammarUtil.containingAssignment(grammarElement2);
if (assignment2 != null && feature.equals(assignment2.getFeature()))
return grammarElement2;
// if (child.hasDirectSemanticElement() && child.getSemanticElement() != obj)
// break;
child = ((ICompositeNode) child).getFirstChild();
}
}
}
if (current.hasDirectSemanticElement() && current.getSemanticElement() != obj)
return null;
current = current.getParent();
}
return null;
}
protected void process(INode node, NodeModelBasedRegionAccess access) {
NodeEObjectRegion tokens = stack.peek();
boolean creator = isEObjectRoot(node);
@ -155,10 +188,13 @@ public class NodeModelBasedRegionAccessBuilder {
stack.push(tokens);
}
if (tokens.getSemanticElement() == null) {
if (node.getParent() == null)
if (node.getParent() == null) {
tokens.setSemantcElement(resource.getContents().get(0));
else if (node.hasDirectSemanticElement())
tokens.setGrammarElement(node.getGrammarElement());
} else if (node.hasDirectSemanticElement()) {
tokens.setSemantcElement(node.getSemanticElement());
tokens.setGrammarElement(findGrammarElement(node, tokens.getSemanticElement()));
}
}
if (include(node)) {
if (node instanceof ICompositeNode) {
@ -179,6 +215,12 @@ public class NodeModelBasedRegionAccessBuilder {
EObject semanticElement = popped.getSemanticElement();
if (semanticElement == null)
throw new IllegalStateException();
if (!stack.isEmpty() && semanticElement.eContainer() != stack.peek().getSemanticElement())
throw new IllegalStateException();
EObject grammarElement = popped.getGrammarElement();
if (grammarElement == null) {
throw new IllegalStateException();
}
NodeEObjectRegion old = eObjToTokens.put(semanticElement, popped);
if (old != null)
throw new IllegalStateException();

View file

@ -7,6 +7,7 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2.regionaccess.internal;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EObject;
@ -14,6 +15,7 @@ import org.eclipse.xtext.formatting2.regionaccess.IEObjectRegion;
import org.eclipse.xtext.formatting2.regionaccess.ITextSegment;
import org.eclipse.xtext.resource.XtextResource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
/**
@ -84,4 +86,9 @@ public class StringBasedRegionAccess extends AbstractRegionAccess {
return string.substring(offset, offset + length);
}
@Override
public List<IEObjectRegion> regionsForAllEObjects() {
return ImmutableList.<IEObjectRegion> copyOf(eObjectToTokens.values());
}
}

View file

@ -8,23 +8,16 @@
package org.eclipse.xtext.formatting2.regionaccess.internal;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.AbstractElement;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
public class StringEObjectRegion extends AbstractEObjectRegion {
private final AbstractElement grammarElement;
public StringEObjectRegion(StringBasedRegionAccess access, AbstractElement grammarElement,
EObject semanticElement) {
public StringEObjectRegion(StringBasedRegionAccess access, EObject grammarElement, EObject semanticElement) {
super(access);
this.grammarElement = grammarElement;
this.setGrammarElement(grammarElement);
this.setSemantcElement(semanticElement);
}
@Override
public AbstractElement getGrammarElement() {
return grammarElement;
}
}

View file

@ -157,7 +157,7 @@ public class TextRegionAccessBuildingSequencer implements ISequenceAcceptor {
return true;
}
protected StringEObjectRegion enterEObject(AbstractElement ele, EObject semanticChild) {
protected StringEObjectRegion enterEObject(EObject ele, EObject semanticChild) {
StringEObjectRegion tokens = new StringEObjectRegion(regionAccess, ele, semanticChild);
regionAccess.add(tokens);
tokens.setLeadingHiddenRegion(last);
@ -201,10 +201,10 @@ public class TextRegionAccessBuildingSequencer implements ISequenceAcceptor {
// not relevant
}
public TextRegionAccessBuildingSequencer withRoot(EObject root) {
public TextRegionAccessBuildingSequencer withRoot(EObject ctx, EObject root) {
this.regionAccess = new StringBasedRegionAccess((XtextResource) root.eResource());
this.last = createHiddenRegion();
this.regionAccess.setRootEObject(enterEObject(null, root));
this.regionAccess.setRootEObject(enterEObject(ctx, root));
return this;
}

View file

@ -129,7 +129,7 @@ public class Serializer implements ISerializer {
EObject context = getContext(obj);
TextRegionAccessBuilder builder = textRegionBuilderProvider.get();
ISerializationDiagnostic.Acceptor errors = ISerializationDiagnostic.EXCEPTION_THROWING_ACCEPTOR;
serialize(obj, context, builder.forSequence(obj), errors);
serialize(obj, context, builder.forSequence(context, obj), errors);
ITextRegionAccess regionAccess = builder.create();
return regionAccess;
}

View file

@ -39,11 +39,11 @@ class RegionAccessTest {
1 foo
'''.toString.trim === '''
0 0 Hidden
Start Simple'foo'
Start Simple'foo' via Root
0 1 Semantic "1" Simple:'1'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 3 Semantic "foo" Simple:name=ID
End Simple'foo'
End Simple'foo' via Root
5 0 Hidden
'''
}
@ -53,12 +53,13 @@ class RegionAccessTest {
2 foo
'''.toString.trim === '''
0 0 Hidden
Start Delegation
Start Delegation via Root
0 1 Semantic "2" Delegation:'2'
1 1 Hidden " " Whitespace:TerminalRule'WS'
Start delegate=Delegate'foo'
Start delegate=Delegate'foo' via Delegation:delegate=Delegate
2 3 Semantic "foo" Delegate:name=ID
End Delegation, delegate=Delegate'foo'
End delegate=Delegate'foo' via Delegation:delegate=Delegate
End Delegation via Root
5 0 Hidden
'''
}
@ -68,11 +69,11 @@ class RegionAccessTest {
3 foo
'''.toString.trim === '''
0 0 Hidden
Start Delegate'foo'
Start Delegate'foo' via Root
0 1 Semantic "3" Unassigned:'3'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 3 Semantic "foo" Delegate:name=ID
End Delegate'foo'
End Delegate'foo' via Root
5 0 Hidden
'''
}
@ -82,14 +83,15 @@ class RegionAccessTest {
4 prefix foo
'''.toString.trim === '''
0 0 Hidden
Start PrefixedUnassigned
Start PrefixedUnassigned via Root
0 1 Semantic "4" PrefixedUnassigned:'4'
1 1 Hidden " " Whitespace:TerminalRule'WS'
Start delegate=Delegate'foo'
Start delegate=Delegate'foo' via PrefixedUnassigned:delegate=PrefixedDelegate
2 6 Semantic "prefix" PrefixedDelegate:'prefix'
8 1 Hidden " " Whitespace:TerminalRule'WS'
9 3 Semantic "foo" Delegate:name=ID
End PrefixedUnassigned, delegate=Delegate'foo'
End delegate=Delegate'foo' via PrefixedUnassigned:delegate=PrefixedDelegate
End PrefixedUnassigned via Root
12 0 Hidden
'''
}
@ -99,18 +101,19 @@ class RegionAccessTest {
5 a + b
'''.toString.trim === '''
0 0 Hidden
Start Add
Start Add via Root
0 1 Semantic "5" Root:'5'
1 1 Hidden " " Whitespace:TerminalRule'WS'
Start left=Named'a'
Start left=Named'a' via Expression:{Add.left=}
2 1 Semantic "a" Primary:name=ID
End left=Named'a'
End left=Named'a' via Expression:{Add.left=}
3 1 Hidden " " Whitespace:TerminalRule'WS'
4 1 Semantic "+" Expression:'+'
5 1 Hidden " " Whitespace:TerminalRule'WS'
Start right=Named'b'
Start right=Named'b' via Expression:right=Primary
6 1 Semantic "b" Primary:name=ID
End Add, right=Named'b'
End right=Named'b' via Expression:right=Primary
End Add via Root
7 0 Hidden
'''
}
@ -120,30 +123,31 @@ class RegionAccessTest {
5 (a + b) + c
'''.toString.trim === '''
0 0 Hidden
Start Add
Start Add via Root
0 1 Semantic "5" Root:'5'
1 1 Hidden " " Whitespace:TerminalRule'WS'
Start left=Add
Start left=Add via Expression:{Add.left=}
2 1 Semantic "(" Parenthesized:'('
3 0 Hidden
Start left=Named'a'
Start left=Named'a' via Expression:{Add.left=}
3 1 Semantic "a" Primary:name=ID
End left=Named'a'
End left=Named'a' via Expression:{Add.left=}
4 1 Hidden " " Whitespace:TerminalRule'WS'
5 1 Semantic "+" Expression:'+'
6 1 Hidden " " Whitespace:TerminalRule'WS'
Start right=Named'b'
Start right=Named'b' via Expression:right=Primary
7 1 Semantic "b" Primary:name=ID
End right=Named'b'
End right=Named'b' via Expression:right=Primary
8 0 Hidden
8 1 Semantic ")" Parenthesized:')'
End left=Add
End left=Add via Expression:{Add.left=}
9 1 Hidden " " Whitespace:TerminalRule'WS'
10 1 Semantic "+" Expression:'+'
11 1 Hidden " " Whitespace:TerminalRule'WS'
Start right=Named'c'
Start right=Named'c' via Expression:right=Primary
12 1 Semantic "c" Primary:name=ID
End Add, right=Named'c'
End right=Named'c' via Expression:right=Primary
End Add via Root
13 0 Hidden
'''
}
@ -153,7 +157,7 @@ class RegionAccessTest {
6 (unassigned foo)
'''.toString.trim === '''
0 0 Hidden
Start Action
Start Action via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -163,7 +167,7 @@ class RegionAccessTest {
14 3 Semantic "foo" Mixed:ID
17 0 Hidden
17 1 Semantic ")" Mixed:')'
End Action
End Action via Root
18 0 Hidden
'''
}
@ -173,7 +177,7 @@ class RegionAccessTest {
6 (unassigned datatype foo)
'''.toString.trim === '''
0 0 Hidden
Start Action
Start Action via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -183,7 +187,7 @@ class RegionAccessTest {
14 12 Semantic "datatyp..." Mixed:Datatype
26 0 Hidden
26 1 Semantic ")" Mixed:')'
End Action
End Action via Root
27 0 Hidden
'''
}
@ -193,7 +197,7 @@ class RegionAccessTest {
6 (unassigned datatype datatype foo)
'''.toString.trim === '''
0 0 Hidden
Start Action
Start Action via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -203,7 +207,7 @@ class RegionAccessTest {
14 21 Semantic "datatyp..." Mixed:Datatype
35 0 Hidden
35 1 Semantic ")" Mixed:')'
End Action
End Action via Root
36 0 Hidden
'''
}
@ -213,13 +217,13 @@ class RegionAccessTest {
6 ()
'''.toString.trim === '''
0 0 Hidden
Start Action
Start Action via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
3 0 Hidden
3 1 Semantic ")" Mixed:')'
End Action
End Action via Root
4 0 Hidden
'''
}
@ -229,7 +233,7 @@ class RegionAccessTest {
6 (())
'''.toString.trim === '''
0 0 Hidden
Start Action
Start Action via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -239,7 +243,7 @@ class RegionAccessTest {
4 1 Semantic ")" Mixed:')'
5 0 Hidden
5 1 Semantic ")" Mixed:')'
End Action
End Action via Root
6 0 Hidden
'''
}
@ -249,7 +253,7 @@ class RegionAccessTest {
6 ((()))
'''.toString.trim === '''
0 0 Hidden
Start Action
Start Action via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -263,7 +267,7 @@ class RegionAccessTest {
6 1 Semantic ")" Mixed:')'
7 0 Hidden
7 1 Semantic ")" Mixed:')'
End Action
End Action via Root
8 0 Hidden
'''
}
@ -273,7 +277,7 @@ class RegionAccessTest {
6 (((foo)))
'''.toString.trim === '''
0 0 Hidden
Start Mixed'foo'
Start Mixed'foo' via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -289,7 +293,7 @@ class RegionAccessTest {
9 1 Semantic ")" Mixed:')'
10 0 Hidden
10 1 Semantic ")" Mixed:')'
End Mixed'foo'
End Mixed'foo' via Root
11 0 Hidden
'''
}
@ -299,14 +303,14 @@ class RegionAccessTest {
6 (child(((foo))))
'''.toString.trim === '''
0 0 Hidden
Start Mixed
Start Mixed via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
3 0 Hidden
3 5 Semantic "child" Mixed:'child'
8 0 Hidden
Start eobj=Mixed'foo'
Start eobj=Mixed'foo' via Mixed:eobj=Mixed
8 1 Semantic "(" Mixed:'('
9 0 Hidden
9 1 Semantic "(" Mixed:'('
@ -320,10 +324,10 @@ class RegionAccessTest {
15 1 Semantic ")" Mixed:')'
16 0 Hidden
16 1 Semantic ")" Mixed:')'
End eobj=Mixed'foo'
End eobj=Mixed'foo' via Mixed:eobj=Mixed
17 0 Hidden
17 1 Semantic ")" Mixed:')'
End Mixed
End Mixed via Root
18 0 Hidden
'''
}
@ -333,7 +337,7 @@ class RegionAccessTest {
6 (datatype foo)
'''.toString.trim === '''
0 0 Hidden
Start Mixed
Start Mixed via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -341,7 +345,7 @@ class RegionAccessTest {
3 12 Semantic "datatyp..." Mixed:datatype=Datatype
15 0 Hidden
15 1 Semantic ")" Mixed:')'
End Mixed
End Mixed via Root
16 0 Hidden
'''
}
@ -351,7 +355,7 @@ class RegionAccessTest {
6 (datatype datatype foo)
'''.toString.trim === '''
0 0 Hidden
Start Mixed
Start Mixed via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -359,7 +363,7 @@ class RegionAccessTest {
3 21 Semantic "datatyp..." Mixed:datatype=Datatype
24 0 Hidden
24 1 Semantic ")" Mixed:')'
End Mixed
End Mixed via Root
25 0 Hidden
'''
}
@ -369,20 +373,20 @@ class RegionAccessTest {
6 (foo) action (ref foo) end
'''.toString.trim === '''
0 0 Hidden
Start AssignedAction
Start AssignedAction via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
Start child=Mixed'foo'
Start child=Mixed'foo' via Mixed:{AssignedAction.child=}
2 1 Semantic "(" Mixed:'('
3 0 Hidden
3 3 Semantic "foo" Mixed:name=ID
6 0 Hidden
6 1 Semantic ")" Mixed:')'
End child=Mixed'foo'
End child=Mixed'foo' via Mixed:{AssignedAction.child=}
7 1 Hidden " " Whitespace:TerminalRule'WS'
8 6 Semantic "action" Mixed:'action'
14 1 Hidden " " Whitespace:TerminalRule'WS'
Start body=Mixed
Start body=Mixed via Mixed:body=Mixed
15 1 Semantic "(" Mixed:'('
16 0 Hidden
16 3 Semantic "ref" Mixed:'ref'
@ -390,10 +394,10 @@ class RegionAccessTest {
20 3 Semantic "foo" Mixed:ref=[Mixed|ID]
23 0 Hidden
23 1 Semantic ")" Mixed:')'
End body=Mixed
End body=Mixed via Mixed:body=Mixed
24 1 Hidden " " Whitespace:TerminalRule'WS'
25 3 Semantic "end" Mixed:'end'
End AssignedAction
End AssignedAction via Root
28 0 Hidden
'''
}
@ -403,7 +407,7 @@ class RegionAccessTest {
6 (lit1)
'''.toString.trim === '''
0 0 Hidden
Start Mixed
Start Mixed via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
2 1 Semantic "(" Mixed:'('
@ -411,7 +415,7 @@ class RegionAccessTest {
3 4 Semantic "lit1" Mixed:lit=Enum
7 0 Hidden
7 1 Semantic ")" Mixed:')'
End Mixed
End Mixed via Root
8 0 Hidden
'''
}
@ -421,19 +425,19 @@ class RegionAccessTest {
6 (foo) action
'''.toString.trim === '''
0 0 Hidden
Start AssignedAction
Start AssignedAction via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
Start child=Mixed'foo'
Start child=Mixed'foo' via Mixed:{AssignedAction.child=}
2 1 Semantic "(" Mixed:'('
3 0 Hidden
3 3 Semantic "foo" Mixed:name=ID
6 0 Hidden
6 1 Semantic ")" Mixed:')'
End child=Mixed'foo'
End child=Mixed'foo' via Mixed:{AssignedAction.child=}
7 1 Hidden " " Whitespace:TerminalRule'WS'
8 6 Semantic "action" Mixed:'action'
End AssignedAction
End AssignedAction via Root
14 0 Hidden
'''
}
@ -443,22 +447,23 @@ class RegionAccessTest {
6 (foo) action action
'''.toString.trim === '''
0 0 Hidden
Start AssignedAction
Start AssignedAction via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
Start child=AssignedAction, child=Mixed'foo'
Start child=AssignedAction via Mixed:{AssignedAction.child=}
Start child=Mixed'foo' via Mixed:{AssignedAction.child=}
2 1 Semantic "(" Mixed:'('
3 0 Hidden
3 3 Semantic "foo" Mixed:name=ID
6 0 Hidden
6 1 Semantic ")" Mixed:')'
End child=Mixed'foo'
End child=Mixed'foo' via Mixed:{AssignedAction.child=}
7 1 Hidden " " Whitespace:TerminalRule'WS'
8 6 Semantic "action" Mixed:'action'
End child=AssignedAction
End child=AssignedAction via Mixed:{AssignedAction.child=}
14 1 Hidden " " Whitespace:TerminalRule'WS'
15 6 Semantic "action" Mixed:'action'
End AssignedAction
End AssignedAction via Root
21 0 Hidden
'''
}
@ -468,20 +473,21 @@ class RegionAccessTest {
6 () action action
'''.toString.trim === '''
0 0 Hidden
Start AssignedAction
Start AssignedAction via Root
0 1 Semantic "6" Root:'6'
1 1 Hidden " " Whitespace:TerminalRule'WS'
Start child=Action, child=AssignedAction
Start child=AssignedAction via Mixed:{AssignedAction.child=}
Start child=Action via Mixed:{AssignedAction.child=}
2 1 Semantic "(" Mixed:'('
3 0 Hidden
3 1 Semantic ")" Mixed:')'
End child=Action
End child=Action via Mixed:{AssignedAction.child=}
4 1 Hidden " " Whitespace:TerminalRule'WS'
5 6 Semantic "action" Mixed:'action'
End child=AssignedAction
End child=AssignedAction via Mixed:{AssignedAction.child=}
11 1 Hidden " " Whitespace:TerminalRule'WS'
12 6 Semantic "action" Mixed:'action'
End AssignedAction
End AssignedAction via Root
18 0 Hidden
'''
}