mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 16:58:56 +00:00
hooked the FlattenedGrammarAccess before the serializer
Signed-off-by: Moritz Eysholdt <moritz.eysholdt@itemis.de>
This commit is contained in:
parent
4a27b82568
commit
d86e9e6442
10 changed files with 274 additions and 31 deletions
|
@ -23,10 +23,12 @@ import org.eclipse.emf.ecore.EClass;
|
|||
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.Action;
|
||||
import org.eclipse.xtext.Assignment;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.Parameter;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
|
||||
import org.eclipse.xtext.serializer.analysis.ISemanticSequencerNfaProvider.ISemState;
|
||||
|
@ -451,16 +453,29 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
}
|
||||
List<String> actions = Lists.newArrayList();
|
||||
List<String> rules = Lists.newArrayList();
|
||||
List<String> params = Lists.newArrayList();
|
||||
for (Action a : relevantActions)
|
||||
actions.add(context2Name.getUniqueActionName(a));
|
||||
for (ParserRule a : relevantRules)
|
||||
rules.add(context2Name.getContextName(grammar, a));
|
||||
Collections.sort(rules);
|
||||
for (IContext ctx : constraint.getContexts()) {
|
||||
Set<Parameter> values = ctx.getParameterValues();
|
||||
if (values != null)
|
||||
for (Parameter param : values) {
|
||||
AbstractRule rule = GrammarUtil.containingRule(param);
|
||||
params.add(rule.getName() + "$" + param.getName());
|
||||
}
|
||||
Collections.sort(rules);
|
||||
}
|
||||
String result = Joiner.on("_").join(rules);
|
||||
if (!actions.isEmpty()) {
|
||||
Collections.sort(actions);
|
||||
result += "_" + Joiner.on('_').join(actions);
|
||||
}
|
||||
if (!params.isEmpty()) {
|
||||
Collections.sort(params);
|
||||
result += "_" + Joiner.on('_').join(params);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,21 +8,30 @@
|
|||
package org.eclipse.xtext.serializer.analysis;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.Parameter;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.grammaranalysis.impl.CfgAdapter;
|
||||
import org.eclipse.xtext.serializer.analysis.SerializationContext.ParameterValueContext;
|
||||
import org.eclipse.xtext.serializer.analysis.SerializationContext.RuleContext;
|
||||
import org.eclipse.xtext.serializer.analysis.SerializerPDA.SerializerPDAElementFactory;
|
||||
import org.eclipse.xtext.util.formallang.FollowerFunctionImpl;
|
||||
import org.eclipse.xtext.util.formallang.Pda;
|
||||
import org.eclipse.xtext.util.formallang.PdaFactory;
|
||||
import org.eclipse.xtext.util.formallang.PdaUtil;
|
||||
import org.eclipse.xtext.util.formallang.Production;
|
||||
import org.eclipse.xtext.xtext.FlattenedGrammarAccess;
|
||||
import org.eclipse.xtext.xtext.OriginalElement;
|
||||
import org.eclipse.xtext.xtext.RuleFilter;
|
||||
import org.eclipse.xtext.xtext.RuleNames;
|
||||
import org.eclipse.xtext.xtext.RuleWithParameterValues;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
@ -66,29 +75,83 @@ public class GrammarPDAProvider implements IGrammarPDAProvider {
|
|||
|
||||
}
|
||||
|
||||
protected static class ToOriginal implements PdaFactory<SerializerPDA, ISerState, RuleCall, AbstractElement> {
|
||||
|
||||
private final SerializerPDAElementFactory delegate;
|
||||
|
||||
public ToOriginal(SerializerPDAElementFactory delegate) {
|
||||
super();
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SerializerPDA create(AbstractElement start, AbstractElement stop) {
|
||||
return delegate.create(original(start), original(stop));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISerState createPop(SerializerPDA pda, AbstractElement token) {
|
||||
return delegate.createPop(pda, original(token));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISerState createPush(SerializerPDA pda, AbstractElement token) {
|
||||
return delegate.createPush(pda, original(token));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISerState createState(SerializerPDA nfa, AbstractElement token) {
|
||||
return delegate.createState(nfa, original(token));
|
||||
}
|
||||
|
||||
protected AbstractElement original(AbstractElement ele) {
|
||||
return ele != null ? OriginalElement.findInEmfObject(ele).getOriginal() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFollowers(SerializerPDA nfa, ISerState owner, Iterable<ISerState> followers) {
|
||||
delegate.setFollowers(nfa, owner, followers);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected SerializerPDAElementFactory factory;
|
||||
|
||||
@Inject
|
||||
protected PdaUtil pdaUtil;
|
||||
|
||||
protected Pda<ISerState, RuleCall> createPDA(Grammar grammar, ParserRule entryRule) {
|
||||
Preconditions.checkArgument(isValidRule(entryRule));
|
||||
SerializerParserRuleCfg cfg = new SerializerParserRuleCfg(grammar, entryRule);
|
||||
protected IContext createContext(ParserRule original, Set<Parameter> params) {
|
||||
IContext context = new RuleContext(null, original);
|
||||
if (params != null && !params.isEmpty())
|
||||
context = new ParameterValueContext(context, params);
|
||||
return context;
|
||||
}
|
||||
|
||||
protected Pda<ISerState, RuleCall> createPDA(Grammar flattened, ParserRule entryRule) {
|
||||
SerializerParserRuleCfg cfg = new SerializerParserRuleCfg(flattened, entryRule);
|
||||
SerializerParserRuleFollowerFunction ff = new SerializerParserRuleFollowerFunction(cfg);
|
||||
SerializerPDA pda = pdaUtil.create(cfg, ff, factory);
|
||||
SerializerPDA pda = pdaUtil.create(cfg, ff, new ToOriginal(factory));
|
||||
return pda;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<IContext, Pda<ISerState, RuleCall>> getGrammarPDAs(Grammar grammar) {
|
||||
RuleNames names = RuleNames.getRuleNames(grammar, true);
|
||||
RuleFilter filter = new RuleFilter();
|
||||
filter.setDiscardTerminalRules(true);
|
||||
filter.setDiscardUnreachableRules(false);
|
||||
filter.setDiscardRuleTypeRef(false);
|
||||
Grammar flattened = new FlattenedGrammarAccess(names, filter).getFlattenedGrammar();
|
||||
Map<IContext, Pda<ISerState, RuleCall>> result = Maps.newLinkedHashMap();
|
||||
for (ParserRule rule : GrammarUtil.allParserRules(grammar))
|
||||
if (isValidRule(rule)) {
|
||||
IContext context = new RuleContext(null, rule);
|
||||
for (ParserRule rule : GrammarUtil.allParserRules(flattened)) {
|
||||
RuleWithParameterValues withParams = RuleWithParameterValues.findInEmfObject(rule);
|
||||
AbstractRule original = withParams.getOriginal();
|
||||
if (original instanceof ParserRule && isValidRule((ParserRule) original)) {
|
||||
IContext context = createContext((ParserRule) original, withParams.getParamValues());
|
||||
Pda<ISerState, RuleCall> pda = createPDA(grammar, rule);
|
||||
result.put(context, pda);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.serializer.analysis;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.Parameter;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
|
||||
/**
|
||||
|
@ -17,11 +20,13 @@ import org.eclipse.xtext.ParserRule;
|
|||
*/
|
||||
public interface IContext extends Comparable<IContext> {
|
||||
|
||||
IContext getParent();
|
||||
EObject getActionOrRule();
|
||||
|
||||
Action getAssignedAction();
|
||||
|
||||
EObject getActionOrRule();
|
||||
Set<Parameter> getParameterValues();
|
||||
|
||||
IContext getParent();
|
||||
|
||||
ParserRule getParserRule();
|
||||
|
||||
|
|
|
@ -14,12 +14,14 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
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.Parameter;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.util.Pair;
|
||||
|
@ -28,6 +30,7 @@ import org.eclipse.xtext.util.Tuples;
|
|||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
@ -57,6 +60,30 @@ public abstract class SerializationContext implements IContext {
|
|||
}
|
||||
}
|
||||
|
||||
public static class ParameterValueContext extends SerializationContext {
|
||||
|
||||
private final Set<Parameter> parameters;
|
||||
|
||||
public ParameterValueContext(IContext parent, Set<Parameter> parameters) {
|
||||
super(parent);
|
||||
this.parameters = ImmutableSet.copyOf(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringInternal() {
|
||||
List<String> names = Lists.newArrayList();
|
||||
for (Parameter p : parameters)
|
||||
names.add(p.getName());
|
||||
return Joiner.on("_").join(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Parameter> getParameterValues() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class RuleContext extends SerializationContext {
|
||||
|
||||
private final ParserRule rule;
|
||||
|
@ -227,6 +254,8 @@ public abstract class SerializationContext implements IContext {
|
|||
return false;
|
||||
if (!Objects.equal(getAssignedAction(), other.getAssignedAction()))
|
||||
return false;
|
||||
if (!Objects.equal(getParameterValues(), other.getParameterValues()))
|
||||
return false;
|
||||
if (!Objects.equal(getType(), other.getType()))
|
||||
return false;
|
||||
return true;
|
||||
|
@ -258,10 +287,16 @@ public abstract class SerializationContext implements IContext {
|
|||
return parent != null ? parent.getType() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Parameter> getParameterValues() {
|
||||
return parent != null ? parent.getParameterValues() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
ParserRule rule = getParserRule();
|
||||
Action action = getAssignedAction();
|
||||
Set<Parameter> parameterValues = getParameterValues();
|
||||
EClass type = getType();
|
||||
int result = 1;
|
||||
if (rule != null)
|
||||
|
@ -269,7 +304,9 @@ public abstract class SerializationContext implements IContext {
|
|||
if (action != null)
|
||||
result *= action.hashCode() * 7;
|
||||
if (type != null)
|
||||
result *= type.hashCode() * 31;
|
||||
result *= type.hashCode() * 19;
|
||||
if (parameterValues != null)
|
||||
result *= parameterValues.hashCode() * 31;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.eclipse.xtext.XtextPackage
|
|||
import org.eclipse.xtext.util.internal.EmfAdaptable
|
||||
|
||||
import static extension org.eclipse.xtext.xtext.RuleWithParameterValues.*
|
||||
import org.eclipse.xtext.TypeRef
|
||||
|
||||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
|
@ -52,7 +53,7 @@ class FlattenedGrammarAccess {
|
|||
var flattenedGrammar = copy(grammar)
|
||||
flattenedGrammar.name = grammar.name
|
||||
var origToCopy = Maps.newLinkedHashMap()
|
||||
val copies = copyRuleStubs(names, origToCopy, filter.getRules(grammar))
|
||||
val copies = copyRuleStubs(names, origToCopy, filter.getRules(grammar), filter.discardRuleTypeRef)
|
||||
flattenedGrammar.rules += copies
|
||||
var calledFrom = copyRuleBodies(copies, origToCopy)
|
||||
flattenedGrammar.setHiddenTokens(grammar, origToCopy)
|
||||
|
@ -221,11 +222,20 @@ class FlattenedGrammarAccess {
|
|||
}
|
||||
return calledFrom
|
||||
}
|
||||
|
||||
def private copyTypeRef(TypeRef ref) {
|
||||
if (ref === null)
|
||||
return null
|
||||
val copy = copy(ref)
|
||||
copy.classifier = ref.classifier
|
||||
return copy
|
||||
}
|
||||
|
||||
def private copyRuleStubs(
|
||||
RuleNames names,
|
||||
Map<RuleWithParameterValues, AbstractRule> origToCopy,
|
||||
List<AbstractRule> rulesToCopy
|
||||
List<AbstractRule> rulesToCopy,
|
||||
boolean discardTypeRef
|
||||
) {
|
||||
val result = <AbstractRule>newArrayList
|
||||
for (AbstractRule rule : rulesToCopy) {
|
||||
|
@ -238,6 +248,9 @@ class FlattenedGrammarAccess {
|
|||
copy.name = ruleName
|
||||
copy.fragment = rule.isFragment
|
||||
copy.wildcard = rule.isWildcard
|
||||
if (!discardTypeRef) {
|
||||
copy.type = copyTypeRef(rule.type)
|
||||
}
|
||||
copy.attachTo(rule, origToCopy)
|
||||
result += copy
|
||||
} else {
|
||||
|
@ -247,6 +260,9 @@ class FlattenedGrammarAccess {
|
|||
copy.name = names.getAntlrRuleName(rule, i)
|
||||
copy.fragment = rule.isFragment
|
||||
copy.wildcard = rule.isWildcard
|
||||
if (!discardTypeRef) {
|
||||
copy.type = copyTypeRef(rule.type)
|
||||
}
|
||||
origToCopy.put(parameterValues, copy)
|
||||
parameterValues.attachToEmfObject(copy)
|
||||
result += copy
|
||||
|
|
|
@ -19,9 +19,11 @@ import org.eclipse.xtext.GrammarUtil;
|
|||
public class RuleFilter {
|
||||
|
||||
private boolean discardUnreachableRules;
|
||||
|
||||
|
||||
private boolean discardTerminalRules;
|
||||
|
||||
|
||||
private boolean discardRuleTypeRef = true;
|
||||
|
||||
public List<AbstractRule> getRules(Grammar grammar) {
|
||||
return GrammarUtil.allRules(grammar);
|
||||
}
|
||||
|
@ -29,7 +31,7 @@ public class RuleFilter {
|
|||
public boolean isDiscardUnreachableRules() {
|
||||
return discardUnreachableRules;
|
||||
}
|
||||
|
||||
|
||||
public void setDiscardUnreachableRules(boolean discardUnreachableRules) {
|
||||
this.discardUnreachableRules = discardUnreachableRules;
|
||||
}
|
||||
|
@ -41,5 +43,13 @@ public class RuleFilter {
|
|||
public void setDiscardTerminalRules(boolean discardTerminalRules) {
|
||||
this.discardTerminalRules = discardTerminalRules;
|
||||
}
|
||||
|
||||
|
||||
public boolean isDiscardRuleTypeRef() {
|
||||
return discardRuleTypeRef;
|
||||
}
|
||||
|
||||
public void setDiscardRuleTypeRef(boolean discardRuleTypeRef) {
|
||||
this.discardRuleTypeRef = discardRuleTypeRef;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -524,4 +524,23 @@ public class ContextPDAProviderTest extends AbstractXtextTests {
|
|||
expected.append(" opt=ID -> stop");
|
||||
assertEquals(expected.toString(), actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameters() throws Exception {
|
||||
String actual = getParserRule("M: 'kw1' s=S<true> | 'kw2' s=S<false>; S <P>: <P> v1=ID | <!P> v2=ID; ");
|
||||
StringBuilder expected = new StringBuilder();
|
||||
expected.append("M:\n");
|
||||
expected.append(" start -> 'kw1', 'kw2'\n");
|
||||
expected.append(" 'kw1' -> (s=S|)\n");
|
||||
expected.append(" 'kw2' -> (|s=S)\n");
|
||||
expected.append(" (s=S|) -> stop\n");
|
||||
expected.append(" (|s=S) -> stop\n");
|
||||
expected.append("S_P:\n");
|
||||
expected.append(" start -> v1=ID\n");
|
||||
expected.append(" v1=ID -> stop\n");
|
||||
expected.append("S:\n");
|
||||
expected.append(" start -> v2=ID\n");
|
||||
expected.append(" v2=ID -> stop");
|
||||
assertEquals(expected.toString(), actual);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -349,7 +349,7 @@ public class ContextTypePDAProviderTest extends AbstractXtextTests {
|
|||
expected.append(" name=ID -> <<F");
|
||||
assertEquals(expected.toString(), actual);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testActionFragment() throws Exception {
|
||||
StringBuilder grammar = new StringBuilder();
|
||||
|
@ -374,4 +374,23 @@ public class ContextTypePDAProviderTest extends AbstractXtextTests {
|
|||
expected.append(" val1=ID -> 'kw1'");
|
||||
assertEquals(expected.toString(), actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameters() throws Exception {
|
||||
String actual = getParserRule("M: 'kw1' s=S<true> | 'kw2' s=S<false>; S <P>: <P> v1=ID | <!P> v2=ID; ");
|
||||
StringBuilder expected = new StringBuilder();
|
||||
expected.append("M_M:\n");
|
||||
expected.append(" start -> 'kw1', 'kw2'\n");
|
||||
expected.append(" 'kw1' -> (s=S|)\n");
|
||||
expected.append(" 'kw2' -> (|s=S)\n");
|
||||
expected.append(" (s=S|) -> stop\n");
|
||||
expected.append(" (|s=S) -> stop\n");
|
||||
expected.append("S_P_S:\n");
|
||||
expected.append(" start -> v1=ID\n");
|
||||
expected.append(" v1=ID -> stop\n");
|
||||
expected.append("S_S:\n");
|
||||
expected.append(" start -> v2=ID\n");
|
||||
expected.append(" v2=ID -> stop");
|
||||
assertEquals(expected.toString(), actual);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -431,4 +431,17 @@ public class GrammarConstraintProviderTest extends AbstractXtextTests {
|
|||
expected.append(" F_Rule returns Rule: name=ID;");
|
||||
assertEquals(expected.toString(), actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameters() throws Exception {
|
||||
String actual = getParserRule("M: 'kw1' s=S<true> | 'kw2' s=S<false>; S <P>: <P> v1=ID | <!P> v2=ID; ");
|
||||
StringBuilder expected = new StringBuilder();
|
||||
expected.append("M_M:\n");
|
||||
expected.append(" M_M returns M: (s=S | s=S);\n");
|
||||
expected.append("S_P_S:\n");
|
||||
expected.append(" S_S$P_S returns S: v1=ID;\n");
|
||||
expected.append("S_S:\n");
|
||||
expected.append(" S_S returns S: v2=ID;");
|
||||
assertEquals(expected.toString(), actual);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ import org.junit.Assert
|
|||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.eclipse.xtext.util.formallang.NfaUtil
|
||||
import org.eclipse.xtext.GrammarUtil
|
||||
import org.eclipse.xtext.util.EmfFormatter
|
||||
|
||||
/**
|
||||
* @author Moritz Eysholdt - Initial contribution and API
|
||||
|
@ -165,6 +168,34 @@ class GrammarPDAProviderTest {
|
|||
'''
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test def void testUnassignedDatatypeRule() {
|
||||
val actual = '''
|
||||
Rule: val=ID Called;
|
||||
Called: 'kw1';
|
||||
'''.toPda
|
||||
val expected = '''
|
||||
Rule:
|
||||
start -> val=ID
|
||||
Called -> stop
|
||||
val=ID -> Called
|
||||
'''
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test def void testUnassignedTerminalRule() {
|
||||
val actual = '''
|
||||
Rule: val=ID Called;
|
||||
terminal Called: 'kw1';
|
||||
'''.toPda
|
||||
val expected = '''
|
||||
Rule:
|
||||
start -> val=ID
|
||||
Called -> stop
|
||||
val=ID -> Called
|
||||
'''
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test def void testUnassignedParserRuleCall() {
|
||||
val actual = '''
|
||||
|
@ -243,7 +274,7 @@ class GrammarPDAProviderTest {
|
|||
'''
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
|
||||
@Test def void testUnorderedGroup2() {
|
||||
val actual = '''
|
||||
Rule: {Rule} ('a' & 'b'? & 'c'* & 'd'+);
|
||||
|
@ -259,7 +290,7 @@ class GrammarPDAProviderTest {
|
|||
'''
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
|
||||
@Test def void testTwoAssignedEObjectRuleCalls() {
|
||||
val actual = '''
|
||||
Rule: foo1=Sub foo2=Sub; Sub: id='id';
|
||||
|
@ -374,21 +405,25 @@ class GrammarPDAProviderTest {
|
|||
'''
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test @Ignore def void testParameter1() {
|
||||
|
||||
@Test def void testParameter1() {
|
||||
val actual = '''
|
||||
M: "kw1" s=S<true> | "kw2" s=S<false>;
|
||||
S <P>: <P> v1=ID | <!P> v2=ID;
|
||||
'''.toPda
|
||||
val expected = '''
|
||||
Greeting:
|
||||
start -> '(', val=ID
|
||||
'(' -> >>Greeting
|
||||
')' -> {Foo.child=}
|
||||
<<Greeting -> ')'
|
||||
>>Greeting -> '(', val=ID
|
||||
val=ID -> <<Greeting, stop
|
||||
{Foo.child=} -> <<Greeting, stop
|
||||
M:
|
||||
start -> 'kw1', 'kw2'
|
||||
'kw1' -> (s=S|)
|
||||
'kw2' -> (|s=S)
|
||||
(s=S|) -> stop
|
||||
(|s=S) -> stop
|
||||
S_P:
|
||||
start -> v1=ID
|
||||
v1=ID -> stop
|
||||
S:
|
||||
start -> v2=ID
|
||||
v2=ID -> stop
|
||||
'''
|
||||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
@ -403,6 +438,8 @@ class GrammarPDAProviderTest {
|
|||
''')
|
||||
validator.assertNoErrors(grammar)
|
||||
val pdas = pdaProvider.getGrammarPDAs(grammar)
|
||||
pdas.values.forEach[assertNoLeakedGrammarElements(grammar, it)]
|
||||
|
||||
// pdas.forEach[p1, p2|p2.toDot(p1.name)]
|
||||
return pdas.keySet.sort.map [
|
||||
'''
|
||||
|
@ -412,6 +449,15 @@ class GrammarPDAProviderTest {
|
|||
].join
|
||||
}
|
||||
|
||||
def private void assertNoLeakedGrammarElements(Grammar grammar, Pda<ISerState, RuleCall> pda) {
|
||||
for (ele : new NfaUtil().collect(pda).map[grammarElement].filterNull) {
|
||||
val actual = GrammarUtil.getGrammar(ele)
|
||||
if (actual !== grammar) {
|
||||
Assert.fail("Element " + EmfFormatter.objPath(ele) + " leaked!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def protected toDot(Pda<ISerState, RuleCall> pda, String name) {
|
||||
val test = Thread.currentThread.stackTrace.get(6).methodName
|
||||
new PdaToDot().draw(pda, "dot2/" + test + "_" + name + ".pdf", "-T pdf")
|
||||
|
|
Loading…
Reference in a new issue