mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 08:48:55 +00:00
[serializer] fixed bug 362581
Syntactic sequencer extension for serialization of optional keywords doesn't work
This commit is contained in:
parent
3f87738752
commit
c6e9930e7a
4 changed files with 239 additions and 74 deletions
|
@ -397,7 +397,9 @@ Workflow {
|
|||
}
|
||||
language = {
|
||||
uri = "classpath:/org/eclipse/xtext/serializer/SyntacticSequencerTestLanguage.xtext"
|
||||
fragment = @TestLanguagesFragments auto-inject {}
|
||||
fragment = @TestLanguagesFragments auto-inject {
|
||||
srcGenOnly = false
|
||||
}
|
||||
}
|
||||
language = {
|
||||
uri = "classpath:/org/eclipse/xtext/serializer/ContextFinderTestLanguage.xtext"
|
||||
|
|
|
@ -8,22 +8,24 @@
|
|||
package org.eclipse.xtext.serializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.CrossReference;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
|
||||
import org.eclipse.xtext.junit.AbstractXtextTests;
|
||||
import org.eclipse.xtext.junit.serializer.DebugSequenceAcceptor;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
import org.eclipse.xtext.nodemodel.ILeafNode;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
|
||||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.serializer.acceptor.ISemanticSequenceAcceptor;
|
||||
import org.eclipse.xtext.serializer.analysis.IGrammarConstraintProvider;
|
||||
import org.eclipse.xtext.serializer.analysis.IGrammarConstraintProvider.IConstraint;
|
||||
import org.eclipse.xtext.serializer.analysis.IGrammarConstraintProvider.IConstraintContext;
|
||||
import org.eclipse.xtext.serializer.acceptor.ISequenceAcceptor;
|
||||
import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic;
|
||||
import org.eclipse.xtext.serializer.sequencer.EmitterNodeIterator;
|
||||
import org.eclipse.xtext.serializer.sequencer.ISemanticSequencer;
|
||||
|
@ -32,7 +34,6 @@ import org.eclipse.xtext.serializer.sequencer.NodeModelSemanticSequencer;
|
|||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
|
@ -41,6 +42,11 @@ import com.google.inject.Provider;
|
|||
*/
|
||||
public class SyntacticSequencerTest extends AbstractXtextTests {
|
||||
|
||||
@Override
|
||||
protected boolean shouldTestSerializer(XtextResource resource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
@ -48,20 +54,103 @@ public class SyntacticSequencerTest extends AbstractXtextTests {
|
|||
getInjector().injectMembers(this);
|
||||
}
|
||||
|
||||
private static class NoEnterNodesDebugSequenceAcceptor extends DebugSequenceAcceptor {
|
||||
private static class Acceptor implements ISequenceAcceptor {
|
||||
|
||||
public NoEnterNodesDebugSequenceAcceptor(boolean printInstantly) {
|
||||
super(printInstantly);
|
||||
public List<String> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<String> result = Lists.newArrayList();
|
||||
|
||||
protected GrammarElementTitleSwitch titles = new GrammarElementTitleSwitch().showAssignments();
|
||||
|
||||
private void add(AbstractElement ele, String token) {
|
||||
result.add(titles.doSwitch(ele) + " -> " + token.trim());
|
||||
}
|
||||
|
||||
public void enterUnassignedParserRuleCall(RuleCall rc) {
|
||||
}
|
||||
|
||||
public void leaveUnssignedParserRuleCall(RuleCall rc) {
|
||||
}
|
||||
|
||||
public void acceptUnassignedAction(Action action) {
|
||||
}
|
||||
|
||||
public void acceptUnassignedDatatype(RuleCall datatypeRC, String token, ICompositeNode node) {
|
||||
add(datatypeRC, token);
|
||||
}
|
||||
|
||||
public void acceptUnassignedEnum(RuleCall enumRC, String token, ICompositeNode node) {
|
||||
add(enumRC, token);
|
||||
}
|
||||
|
||||
public void acceptUnassignedKeyword(Keyword keyword, String token, ILeafNode node) {
|
||||
add(keyword, token);
|
||||
}
|
||||
|
||||
public void acceptUnassignedTerminal(RuleCall terminalRC, String token, ILeafNode node) {
|
||||
add(terminalRC, token);
|
||||
}
|
||||
|
||||
public void acceptAssignedCrossRefDatatype(RuleCall datatypeRC, String token, EObject value, int index,
|
||||
ICompositeNode node) {
|
||||
add(datatypeRC, token);
|
||||
}
|
||||
|
||||
public void acceptAssignedCrossRefEnum(RuleCall enumRC, String token, EObject value, int index,
|
||||
ICompositeNode node) {
|
||||
add(enumRC, token);
|
||||
}
|
||||
|
||||
public void acceptAssignedCrossRefTerminal(RuleCall terminalRC, String token, EObject value, int index,
|
||||
ILeafNode node) {
|
||||
add(terminalRC, token);
|
||||
}
|
||||
|
||||
public void acceptAssignedDatatype(RuleCall datatypeRC, String token, Object value, int index,
|
||||
ICompositeNode node) {
|
||||
add(datatypeRC, token);
|
||||
}
|
||||
|
||||
public void acceptAssignedEnum(RuleCall enumRC, String token, Object value, int index, ICompositeNode node) {
|
||||
add(enumRC, token);
|
||||
}
|
||||
|
||||
public void acceptAssignedKeyword(Keyword keyword, String token, Boolean value, int index, ILeafNode node) {
|
||||
add(keyword, token);
|
||||
}
|
||||
|
||||
public void acceptAssignedKeyword(Keyword keyword, String token, String value, int index, ILeafNode node) {
|
||||
add(keyword, token);
|
||||
}
|
||||
|
||||
public void acceptAssignedTerminal(RuleCall terminalRC, String token, Object value, int index, ILeafNode node) {
|
||||
add(terminalRC, token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterAssignedAction(Action action, EObject semanticChild, ICompositeNode node) {
|
||||
return super.enterAssignedAction(action, semanticChild, NO_NODE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterAssignedParserRuleCall(RuleCall rc, EObject newCurrent, ICompositeNode node) {
|
||||
return super.enterAssignedParserRuleCall(rc, newCurrent, NO_NODE);
|
||||
public boolean enterAssignedParserRuleCall(RuleCall rc, EObject semanticChild, ICompositeNode node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
|
||||
}
|
||||
|
||||
public void leaveAssignedAction(Action action, EObject semanticChild) {
|
||||
}
|
||||
|
||||
public void leaveAssignedParserRuleCall(RuleCall rc, EObject semanticChild) {
|
||||
}
|
||||
|
||||
public void acceptComment(AbstractRule rule, String token, ILeafNode node) {
|
||||
}
|
||||
|
||||
public void acceptWhitespace(AbstractRule rule, String token, ILeafNode node) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,61 +159,33 @@ public class SyntacticSequencerTest extends AbstractXtextTests {
|
|||
|
||||
@Inject
|
||||
private Provider<ISyntacticSequencer> syntacticSequencerProvider;
|
||||
|
||||
@Inject
|
||||
|
||||
@Inject
|
||||
private NodeModelSemanticSequencer nmSequencer;
|
||||
|
||||
private void testSequence(String stringModel) throws Exception {
|
||||
EObject model = getModel(stringModel);
|
||||
EObject context = nmSequencer.findContexts(model, true, null).iterator().next();
|
||||
DebugSequenceAcceptor actual = new NoEnterNodesDebugSequenceAcceptor(false);
|
||||
ISemanticSequencer semanticSequencer = semanticSequencerProvider.get();
|
||||
ISyntacticSequencer syntacticSequencer = syntacticSequencerProvider.get();
|
||||
semanticSequencer
|
||||
.init((ISemanticSequenceAcceptor) syntacticSequencer, ISerializationDiagnostic.STDERR_ACCEPTOR);
|
||||
syntacticSequencer.init(context, model, actual, ISerializationDiagnostic.STDERR_ACCEPTOR);
|
||||
semanticSequencer.createSequence(context, model);
|
||||
|
||||
// ((IHiddenTokenSequencerOwner) recSequencer).setHiddenTokenSequencer(get(PassThroughHiddenTokenSequencer.class));
|
||||
// recSequencer.createSequence(context, model, actual, ISerializationDiagnostic.STDERR_ACCEPTOR);
|
||||
// System.out.println(actual);
|
||||
// System.out.println(NodeModelUtils.compactDump(NodeModelUtils.findActualNodeFor(model), false));
|
||||
assertEquals(Joiner.on("\n").join(getNodeSequence(model)), Joiner.on("\n").join(actual.getColumn(4)));
|
||||
Acceptor actual = new Acceptor();
|
||||
ISemanticSequencer semanticSeq = semanticSequencerProvider.get();
|
||||
ISyntacticSequencer syntacticSeq = syntacticSequencerProvider.get();
|
||||
semanticSeq.init((ISemanticSequenceAcceptor) syntacticSeq, ISerializationDiagnostic.STDERR_ACCEPTOR);
|
||||
syntacticSeq.init(context, model, actual, ISerializationDiagnostic.STDERR_ACCEPTOR);
|
||||
semanticSeq.createSequence(context, model);
|
||||
assertEquals(Joiner.on("\n").join(getNodeSequence(model)), Joiner.on("\n").join(actual.getResult()));
|
||||
}
|
||||
|
||||
// public void testXtext() throws Exception {
|
||||
// with(XtextStandaloneSetup.class);
|
||||
// Grammar model = (Grammar) new XtextResourceSet()
|
||||
// .getResource(URI.createURI("classpath:/org/eclipse/xtext/Xtext.xtext"), true).getContents().get(0);
|
||||
// IRecursiveSequencer recSequencer = get(IRecursiveSequencer.class);
|
||||
// DebugSequenceAcceptor actual = new NoEnterNodesDebugSequenceAcceptor(false);
|
||||
// ((IHiddenTokenSequencerOwner) recSequencer).setHiddenTokenSequencer(get(PassThroughHiddenTokenSequencer.class));
|
||||
// recSequencer.createSequence(/*syn, semSequencer,*/getGrammarAccess().getGrammar().getRules().get(0), model,
|
||||
// actual, ISerializationDiagnostic.STDERR_ACCEPTOR);
|
||||
// // System.out.println(actual);
|
||||
// // System.out.println(NodeModelUtils.compactDump(NodeModelUtils.getNode(model), false));
|
||||
// assertEquals(Join.join("\n", getNodeSequence(model)), Join.join("\n", actual.getColumn(4)));
|
||||
// }
|
||||
|
||||
public void testMandatoryKeywords() throws Exception {
|
||||
List<IConstraintContext> ctxts = get(IGrammarConstraintProvider.class).getConstraints(
|
||||
getGrammarAccess().getGrammar());
|
||||
List<String> result = Lists.newArrayList();
|
||||
Set<IConstraint> visited = Sets.newHashSet();
|
||||
for (IConstraintContext ctx : ctxts) {
|
||||
result.add(ctx.toString());
|
||||
for (IConstraint c : ctx.getConstraints())
|
||||
if (visited.add(c))
|
||||
result.add(" " + c.toString());
|
||||
}
|
||||
// System.out.println(Joiner.on("\n").join(result));
|
||||
|
||||
// SyntacticSequencerPDA2ExtendedDot.drawGrammar(get(ISyntacticSequencerPDAProvider.class),
|
||||
// "pdf/syntacticSequencerTest-PDA.pdf", get(IGrammarAccess.class).getGrammar());
|
||||
// new SequenceParserPDA2Dot(get(ISyntacticSequencerPDAProvider.class)).draw(get(IGrammarAccess.class)
|
||||
// .getGrammar(), "pdf/syntacticSequencerTest-PDA.pdf", "-T pdf");
|
||||
|
||||
testSequence("#1 a kw1 b kw2 kw3 c kw4");
|
||||
private void testSequence(String inModel, String outModel) throws Exception {
|
||||
EObject inObj = getModel(inModel);
|
||||
EObject outObj = getModel(outModel);
|
||||
EObject context = nmSequencer.findContexts(inObj, true, null).iterator().next();
|
||||
Acceptor actual = new Acceptor();
|
||||
ISemanticSequencer semanticSeq = semanticSequencerProvider.get();
|
||||
ISyntacticSequencer syntacticSeq = syntacticSequencerProvider.get();
|
||||
semanticSeq.init((ISemanticSequenceAcceptor) syntacticSeq, ISerializationDiagnostic.STDERR_ACCEPTOR);
|
||||
syntacticSeq.init(context, inObj, actual, ISerializationDiagnostic.STDERR_ACCEPTOR);
|
||||
semanticSeq.createSequence(context, inObj);
|
||||
assertEquals(Joiner.on("\n").join(getNodeSequence(outObj)), Joiner.on("\n").join(actual.getResult()));
|
||||
}
|
||||
|
||||
private List<String> getNodeSequence(EObject model) {
|
||||
|
@ -133,14 +194,20 @@ public class SyntacticSequencerTest extends AbstractXtextTests {
|
|||
EmitterNodeIterator ni = new EmitterNodeIterator(NodeModelUtils.findActualNodeFor(model));
|
||||
while (ni.hasNext()) {
|
||||
INode next = ni.next();
|
||||
if (next instanceof ILeafNode)
|
||||
result.add(titleSwitch.doSwitch(next.getGrammarElement()) + " -> " + next.getText());
|
||||
if (next instanceof ICompositeNode)
|
||||
result.add(titleSwitch.doSwitch(next.getGrammarElement()));
|
||||
EObject ele = next.getGrammarElement() instanceof CrossReference ? ((CrossReference) next
|
||||
.getGrammarElement()).getTerminal() : next.getGrammarElement();
|
||||
if (next instanceof ILeafNode || GrammarUtil.isDatatypeRuleCall(ele))
|
||||
result.add(titleSwitch.doSwitch(ele) + " -> " + next.getText().trim());
|
||||
else if (next instanceof ICompositeNode)
|
||||
result.add(titleSwitch.doSwitch(ele));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void testMandatoryKeywords() throws Exception {
|
||||
testSequence("#1 a kw1 b kw2 kw3 c kw4");
|
||||
}
|
||||
|
||||
public void testExp0_a() throws Exception {
|
||||
testSequence("#2 a + b + c + d");
|
||||
}
|
||||
|
@ -200,4 +267,24 @@ public class SyntacticSequencerTest extends AbstractXtextTests {
|
|||
public void testBooleanAlternative_b() throws Exception {
|
||||
testSequence("#6 kw2");
|
||||
}
|
||||
|
||||
public void testUnassignedDatatype() throws Exception {
|
||||
testSequence("#7 foo kw1", "#7 foo matched 1");
|
||||
}
|
||||
|
||||
public void testOpionalSingleTransition() throws Exception {
|
||||
testSequence("#8 kw1 foo", "#8 matched 2 foo");
|
||||
}
|
||||
|
||||
public void testOpionalManyTransition() throws Exception {
|
||||
testSequence("#9 kw1 foo", "#9 matched 3 foo");
|
||||
}
|
||||
|
||||
public void testMandatoryManyTransition() throws Exception {
|
||||
testSequence("#10 kw1 foo", "#10 matched 4 foo");
|
||||
}
|
||||
|
||||
public void testAlternativeTransition() throws Exception {
|
||||
testSequence("#11 kw1 foo", "#11 matched 5 foo");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ generate syntacticsequencertest "http://www.eclipse.org/2009/tmf/xtext/syntactic
|
|||
|
||||
Model:
|
||||
x1=MandatoryKeywords | x2=Exp0 | x3=Exp1 | x4=Exp2 | x5=SingleCrossReference | x6=BooleanAlternative |
|
||||
x7=UnassignedDatatype | x8=AmbiguousTransition;
|
||||
x7=UnassignedDatatype | x8=OptionalSingleTransition | x9=OptionalManyTransition | x10=MandatoryManyTransition |
|
||||
x11=AlternativeTransition;
|
||||
|
||||
MandatoryKeywords:
|
||||
"#1" val1=ID "kw1" val2=ID "kw2" "kw3" val3=ID "kw4";
|
||||
|
@ -67,10 +68,19 @@ BooleanAlternativeLiteral:
|
|||
{BooleanAlternativeLiteral} ("kw1" | isTrue?="kw2");
|
||||
|
||||
UnassignedDatatype:
|
||||
"#7" val=ID UnassignedDatatypeRule;
|
||||
"#7" val=ID KW1;
|
||||
|
||||
UnassignedDatatypeRule:
|
||||
"kw1";
|
||||
KW1:
|
||||
"kw1" | "matched" INT?;
|
||||
|
||||
AmbiguousTransition:
|
||||
"#8" "kw1"? val=ID;
|
||||
OptionalSingleTransition:
|
||||
"#8" KW1? val=ID;
|
||||
|
||||
OptionalManyTransition:
|
||||
"#9" KW1* val=ID;
|
||||
|
||||
MandatoryManyTransition:
|
||||
"#10" KW1+ val=ID;
|
||||
|
||||
AlternativeTransition:
|
||||
"#11" (KW1 | "kw2") val=ID;
|
||||
|
|
|
@ -1,4 +1,70 @@
|
|||
package org.eclipse.xtext.serializer.serializer;
|
||||
|
||||
public class SyntacticSequencerTestLanguageSyntacticSequencer extends AbstractSyntacticSequencerTestLanguageSyntacticSequencer {
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider.ISynNavigable;
|
||||
import org.eclipse.xtext.serializer.services.SyntacticSequencerTestLanguageGrammarAccess;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class SyntacticSequencerTestLanguageSyntacticSequencer extends
|
||||
AbstractSyntacticSequencerTestLanguageSyntacticSequencer {
|
||||
|
||||
private SyntacticSequencerTestLanguageGrammarAccess ga;
|
||||
|
||||
@Inject
|
||||
protected void asetGa(IGrammarAccess ga) {
|
||||
this.ga = (SyntacticSequencerTestLanguageGrammarAccess) ga;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getKW1Token(EObject semanticObject, RuleCall ruleCall, INode node) {
|
||||
return "matched 1";
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: 'kw2' | KW1
|
||||
*/
|
||||
@Override
|
||||
protected void emit_AlternativeTransition_KW1ParserRuleCall_1_0_or_Kw2Keyword_1_1(EObject semanticObject,
|
||||
ISynNavigable transition, List<INode> nodes) {
|
||||
ICompositeNode node = (ICompositeNode) nodes.get(0);
|
||||
acceptUnassignedDatatype(ga.getAlternativeTransitionAccess().getKW1ParserRuleCall_1_0(), "matched 5", node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: KW1+
|
||||
*/
|
||||
@Override
|
||||
protected void emit_MandatoryManyTransition_KW1ParserRuleCall_1_p(EObject semanticObject, ISynNavigable transition,
|
||||
List<INode> nodes) {
|
||||
ICompositeNode node = (ICompositeNode) nodes.get(0);
|
||||
acceptUnassignedDatatype(ga.getMandatoryManyTransitionAccess().getKW1ParserRuleCall_1(), "matched 4", node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: KW1*
|
||||
*/
|
||||
@Override
|
||||
protected void emit_OptionalManyTransition_KW1ParserRuleCall_1_a(EObject semanticObject, ISynNavigable transition,
|
||||
List<INode> nodes) {
|
||||
ICompositeNode node = (ICompositeNode) nodes.get(0);
|
||||
acceptUnassignedDatatype(ga.getOptionalManyTransitionAccess().getKW1ParserRuleCall_1(), "matched 3", node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: KW1?
|
||||
*/
|
||||
@Override
|
||||
protected void emit_OptionalSingleTransition_KW1ParserRuleCall_1_q(EObject semanticObject,
|
||||
ISynNavigable transition, List<INode> nodes) {
|
||||
ICompositeNode node = (ICompositeNode) nodes.get(0);
|
||||
acceptUnassignedDatatype(ga.getOptionalSingleTransitionAccess().getKW1ParserRuleCall_1(), "matched 2", node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue