[serializer] fixed bug 362581

Syntactic sequencer extension for serialization
of optional keywords doesn't work
This commit is contained in:
Moritz Eysholdt 2011-11-09 13:03:32 +01:00
parent 3f87738752
commit c6e9930e7a
4 changed files with 239 additions and 74 deletions

View file

@ -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"

View file

@ -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");
}
}

View file

@ -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;

View file

@ -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);
}
}