diff --git a/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang/NfaUtil.java b/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang/NfaUtil.java
index d66b208c2..96e1a0d30 100644
--- a/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang/NfaUtil.java
+++ b/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang/NfaUtil.java
@@ -168,6 +168,10 @@ public class NfaUtil {
return null;
}
+ public > boolean canReach(Nfa nfa, Predicate matcher) {
+ return find(nfa, Collections.singleton(nfa.getStart()), matcher) != null;
+ }
+
public > boolean canReach(Nfa nfa, S state, Predicate matcher) {
return find(nfa, Collections.singleton(state), matcher) != null;
}
@@ -513,5 +517,5 @@ public class NfaUtil {
public > Nfa sort(Nfa nfa, Map comparator) {
return sort(nfa, new MappedComparator(comparator));
}
-
+
}
diff --git a/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang/PdaUtil.java b/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang/PdaUtil.java
index 50f0d7b64..a011cbabb 100644
--- a/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang/PdaUtil.java
+++ b/plugins/org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang/PdaUtil.java
@@ -278,7 +278,8 @@ public class PdaUtil {
public final long UNREACHABLE = Long.MAX_VALUE;
- public boolean canReach(Pda pda, S state, Iterator
stack, Predicate matches, Predicate canPass) {
+ public boolean canReach(Pda pda, S state, Iterator
stack, Predicate matches,
+ Predicate canPass) {
return distanceTo(pda, Collections.singleton(state), stack, matches, canPass) != UNREACHABLE;
}
@@ -594,6 +595,26 @@ public class PdaUtil {
return null;
}
+ public List collectReachable(Pda pda, final Function function) {
+ final List result = Lists.newArrayList();
+ Iterator stack = Collections.
emptyList().iterator();
+ Predicate matches = Predicates. alwaysFalse();
+ Predicate canPass = new Predicate() {
+ @Override
+ public boolean apply(S input) {
+ R r = function.apply(input);
+ if (r != null) {
+ result.add(r);
+ return false;
+ } else {
+ return true;
+ }
+ }
+ };
+ trace(pda, Collections.singleton(pda.getStart()), stack, matches, canPass);
+ return result;
+ }
+
protected TraceItem trace(Pda pda, Iterable starts, Iterator
stack, Predicate matches,
Predicate canPass) {
StackItem
stackItem = createStack(stack);
@@ -693,75 +714,36 @@ public class PdaUtil {
return filterEdges(pda, traverser, factory);
}
- // public IPdaAdapter parse(String pda) {
- // Pattern node = Pattern.compile("([a-z-A-Z0-9]*)\\[([a-z-A-Z0-9,= ]*)\\]");
- // Pattern transition = Pattern.compile("([a-z-A-Z0-9]*) -> ([a-z-A-Z0-9]*)");
- // final Set starts = Sets.newLinkedHashSet();
- // final Set finals = Sets.newLinkedHashSet();
- // final Multimap followers = HashMultimap.create();
- // final Map pushs = Maps.newLinkedHashMap();
- // final Map pops = Maps.newLinkedHashMap();
- // for (String line : pda.split("\\n")) {
- // line = line.trim();
- // Matcher nodeMatcher = node.matcher(line);
- // if (nodeMatcher.find()) {
- // String name = nodeMatcher.group(1);
- // String[] args = nodeMatcher.group(2).split(",");
- // for (String arg : args) {
- // String[] a = arg.split("=");
- // String argKey, argValue;
- // if (a.length > 1) {
- // argKey = a[0];
- // argValue = a[1];
- // } else {
- // argKey = arg;
- // argValue = null;
- // }
- // if ("start".equals(argKey))
- // starts.add(name);
- // else if ("final".equals(argKey))
- // finals.add(name);
- // else if ("push".equals(argKey))
- // pushs.put(name, argValue);
- // else if ("pop".equals(argKey))
- // pops.put(name, argValue);
- // else
- // throw new RuntimeException("unknown state argument key: '" + argKey + "'");
- // }
- // } else {
- // Matcher transitionMatcher = transition.matcher(line);
- // if (transitionMatcher.find())
- // followers.put(transitionMatcher.group(1), transitionMatcher.group(2));
- // else
- // throw new RuntimeException("Could not parse line: '" + line + "'");
- // }
- //
- // }
- // return new IPdaAdapter() {
- //
- // public String getToken(String owner) {
- // return null;
- // }
- //
- // public Iterable getStartStates() {
- // return starts;
- // }
- //
- // public Iterable getFollowers(String node) {
- // return followers.get(node);
- // }
- //
- // public Iterable getFinalStates() {
- // return finals;
- // }
- //
- // public String getPush(String state) {
- // return pushs.get(state);
- // }
- //
- // public String getPop(String state) {
- // return pops.get(state);
- // }
- // };
- // }
+ public > Map > collectPopsAndPushs(Pda pda) {
+ Map
> result = Maps.newLinkedHashMap();
+ for (S s : nfaUtil.collect(pda)) {
+ P push = pda.getPush(s);
+ if (push != null) {
+ Pair o = result.get(push);
+ Pair n = Tuples.create(s, o == null ? null : o.getSecond());
+ result.put(push, n);
+ }
+ P pop = pda.getPop(s);
+ if (pop != null) {
+ Pair o = result.get(pop);
+ Pair n = Tuples.create(o == null ? null : o.getFirst(), s);
+ result.put(pop, n);
+ }
+ }
+ return result;
+ }
+
+ public > Map mapPopAndPush(Pda pda) {
+ Map
> popsAndPushs = collectPopsAndPushs(pda);
+ Map result = Maps.newLinkedHashMap();
+ for (Pair p : popsAndPushs.values()) {
+ S push = p.getFirst();
+ S pop = p.getSecond();
+ if (push != null && pop != null) {
+ result.put(push, pop);
+ result.put(pop, push);
+ }
+ }
+ return result;
+ }
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextPDAProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextPDAProvider.java
index 0b7ffd36e..c91fffa5e 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextPDAProvider.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextPDAProvider.java
@@ -7,26 +7,34 @@
*******************************************************************************/
package org.eclipse.xtext.serializer.analysis;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.Action;
+import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.RuleCall;
-import org.eclipse.xtext.grammaranalysis.impl.CfgAdapter;
-import org.eclipse.xtext.serializer.analysis.SerializerPDA.SerializerPDACloneFactory;
+import org.eclipse.xtext.serializer.analysis.ISerState.SerStateType;
import org.eclipse.xtext.serializer.analysis.SerializerPDA.SerializerPDAElementFactory;
-import org.eclipse.xtext.serializer.analysis.SerializerPDA.SerializerPDAGetToken;
-import org.eclipse.xtext.util.formallang.FollowerFunctionImpl;
+import org.eclipse.xtext.serializer.analysis.SerializerPDA.SerializerPDAState;
+import org.eclipse.xtext.util.Pair;
+import org.eclipse.xtext.util.Tuples;
+import org.eclipse.xtext.util.formallang.NfaUtil;
import org.eclipse.xtext.util.formallang.Pda;
import org.eclipse.xtext.util.formallang.PdaUtil;
-import org.eclipse.xtext.util.formallang.Production;
-import com.google.common.base.Function;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -37,170 +45,221 @@ import com.google.inject.Singleton;
@Singleton
public class ContextPDAProvider implements IContextPDAProvider {
- protected class ExpandRuleCalls implements Function> {
- @Override
- public Pda apply(ISerState input) {
- if (GrammarUtil.isUnassignedEObjectRuleCall(input.getGrammarElement()))
- return getContextPDA((((RuleCall) input.getGrammarElement()).getRule()));
- return null;
+ protected static class CallStack {
+ private final RuleCall call;
+ private final CallStack parent;
+ private final Set visited = Sets.newHashSet();
+
+ public CallStack(CallStack parent, RuleCall call) {
+ super();
+ this.parent = parent;
+ this.call = call;
+ }
+
+ public boolean isLoop() {
+ CallStack current = parent;
+ int counter = 0;
+ while (current != null) {
+ if (current.call == call)
+ counter++;
+ if (counter >= 2)
+ return true;
+ current = current.parent;
+ }
+ return false;
}
}
- protected static class SerializerActionCfg extends CfgAdapter {
- protected Action context;
+ private final Map>> cache = Maps.newHashMap();
- public SerializerActionCfg(Action context) {
- super(GrammarUtil.getGrammar(context));
- this.context = context;
- }
+ @Inject
+ private SerializerPDAElementFactory factory;
- @Override
- public AbstractElement getCall(AbstractElement ele) {
- return null;
- }
+ @Inject
+ private IGrammarPDAProvider grammarPdaProvider;
- @Override
- public AbstractElement getRoot() {
- return GrammarUtil.containingRule(context).getAlternatives();
- }
- }
-
- protected static class SerializerActionFollowerFunction extends
- FollowerFunctionImpl {
-
- protected Action actionCtx;
-
- public SerializerActionFollowerFunction(Production production, Action context) {
- super(production);
- this.actionCtx = context;
- }
-
- @Override
- public Iterable getFollowers(AbstractElement element) {
- Set result = Sets.newLinkedHashSet();
- for (AbstractElement ele : super.getFollowers(element))
- if (ele == null) {
- } else if (actionCtx == ele)
- result.add(null);
- else if (!GrammarUtil.isAssignedAction(ele))
- result.add(ele);
- return result;
- }
-
- @Override
- public Iterable getStarts(AbstractElement root) {
- Set result = Sets.newLinkedHashSet();
- for (Action act : GrammarUtil.containedActions(root))
- if (act.getFeature() != null)
- result.add(act);
- for (AbstractElement ele : super.getStarts(root))
- if (ele == null) {
- } else if (actionCtx == ele) {
- result.add(null);
- } else if (!GrammarUtil.isAssignedAction(ele))
- result.add(ele);
- return result;
- }
-
- }
-
- protected static class SerializerParserRuleCfg extends CfgAdapter {
- protected ParserRule context;
-
- public SerializerParserRuleCfg(ParserRule context) {
- super(GrammarUtil.getGrammar(context));
- this.context = context;
- }
-
- @Override
- public AbstractElement getCall(AbstractElement ele) {
- if (ele instanceof RuleCall && !GrammarUtil.isAssigned(ele)
- && GrammarUtil.isEObjectRuleCall(ele))
- return ((RuleCall) ele).getRule().getAlternatives();
- return null;
- }
-
- @Override
- public AbstractElement getRoot() {
- return context.getAlternatives();
- }
- }
-
- protected static class SerializerParserRuleFollowerFunction extends
- FollowerFunctionImpl {
-
- protected ParserRule ruleCtx;
-
- public SerializerParserRuleFollowerFunction(Production production,
- ParserRule context) {
- super(production);
- this.ruleCtx = context;
- }
-
- @Override
- public Iterable getFollowers(AbstractElement element) {
- Set result = Sets.newLinkedHashSet();
- for (AbstractElement ele : super.getFollowers(element))
- if (ele == null)
- result.add(null);
- else if (!GrammarUtil.isAssignedAction(ele))
- result.add(ele);
- return result;
- }
-
- @Override
- public Iterable getStarts(AbstractElement root) {
- Set result = Sets.newLinkedHashSet();
- for (Action act : GrammarUtil.containedActions(root))
- if (act.getFeature() != null)
- result.add(act);
- for (AbstractElement ele : super.getStarts(root))
- if (ele == null)
- result.add(null);
- else if (!GrammarUtil.isAssignedAction(ele))
- result.add(ele);
- return result;
- }
-
- }
-
- protected Map> cache = Maps.newHashMap();
+ @Inject
+ private NfaUtil nfaUtil;
@Inject
protected PdaUtil pdaUtil;
- protected Pda createPDA(Action action) {
- SerializerActionCfg cfg = new SerializerActionCfg(action);
- SerializerActionFollowerFunction ff = new SerializerActionFollowerFunction(cfg, action);
- SerializerPDAElementFactory fact = new SerializerPDAElementFactory();
- Pda actionpda = pdaUtil.create(cfg, ff, fact);
- SerializerPDAGetToken getToken = new SerializerPDAGetToken();
- Pda expandedpda = pdaUtil.expand(actionpda, new ExpandRuleCalls(), getToken, fact);
- Pda filteredpda = pdaUtil.filterOrphans(expandedpda, new SerializerPDACloneFactory());
- return filteredpda;
+ protected void collectExtracted(ISerState orig, Collection extends ISerState> precedents, SerializerPDAState copy,
+ Map, SerializerPDAState> oldToNew, final CallStack inTop,
+ SerializerPDAState start) {
+ for (ISerState pre : precedents) {
+ CallStack top = inTop;
+ AbstractElement element = pre.getGrammarElement();
+ switch (pre.getType()) {
+ case START:
+ if (top.call == null)
+ connect(start, copy);
+ continue;
+ case POP:
+ top = new CallStack(top, (RuleCall) element);
+ if (top.isLoop())
+ continue;
+ break;
+ case PUSH:
+ if (top.call == null) {
+ connect(start, copy);
+ continue;
+ } else if (top.call == element) {
+ top = top.parent;
+ } else {
+ continue;
+ }
+ default:
+ break;
+ }
+ Pair key = Tuples.create(element, pre.getType());
+ SerializerPDAState pre2 = oldToNew.get(key);
+ if (pre2 == null) {
+ pre2 = new SerializerPDAState(element, pre.getType());
+ oldToNew.put(key, pre2);
+ }
+ if (GrammarUtil.isAssignedAction(pre.getGrammarElement()) /* && pre.getType() != STOP */) {
+ Set entries = collectPushForAction(pre);
+ collectExtracted(pre, entries, pre2, oldToNew, top, start);
+ } else {
+ if (top.visited.add(pre))
+ collectExtracted(pre, pre.getPrecedents(), pre2, oldToNew, top, start);
+ }
+ connect(pre2, copy);
+ }
}
- protected Pda createPDA(EObject context, Pda result) {
- if (context instanceof ParserRule)
- return createPDA((ParserRule) context);
- else if (context instanceof Action)
- return createPDA((Action) context);
- throw new IllegalStateException("illegal context");
- }
-
- protected Pda createPDA(ParserRule rule) {
- SerializerParserRuleCfg cfg = new SerializerParserRuleCfg(rule);
- SerializerParserRuleFollowerFunction ff = new SerializerParserRuleFollowerFunction(cfg, rule);
- Pda pda = pdaUtil.create(cfg, ff, new SerializerPDAElementFactory());
- return pdaUtil.filterOrphans(pda, new SerializerPDACloneFactory());
- }
-
- @Override
- public Pda getContextPDA(EObject context) {
- Pda result = cache.get(context);
- if (result == null)
- cache.put(context, result = createPDA(context, result));
+ protected Set collectPushForAction(ISerState action) {
+ ParserRule rule = GrammarUtil.containingParserRule(action.getGrammarElement());
+ LinkedHashSet result = Sets. newLinkedHashSet();
+ collectPushForAction(action, rule, result, Sets. newHashSet());
return result;
}
+ protected void collectPushForAction(ISerState state, ParserRule rule, Set result,
+ Set visited) {
+ if (!visited.add(state))
+ return;
+ switch (state.getType()) {
+ case START:
+ result.add(state);
+ return;
+ case PUSH:
+ AbstractElement element = state.getGrammarElement();
+ if (element instanceof RuleCall && ((RuleCall) element).getRule() == rule) {
+ result.add(state);
+ return;
+ }
+ default:
+ break;
+ }
+ List extends ISerState> precedents = state.getPrecedents();
+ for (ISerState pre : precedents)
+ collectPushForAction(pre, rule, result, visited);
+ }
+
+ protected void connect(SerializerPDAState precedent, SerializerPDAState follower) {
+ if (precedent == null || follower == null)
+ return;
+ if (follower.getPrecedents().contains(precedent))
+ return;
+ follower.getPrecedents().add(precedent);
+ precedent.getFollowers().add(follower);
+ }
+
+ protected Pda extract(ISerState last) {
+ SerializerPDA result = factory.create(null, null);
+ HashMap, SerializerPDAState> oldToNew = Maps.newHashMap();
+ CallStack callStack = new CallStack(null, null);
+ collectExtracted(last, last.getPrecedents(), result.getStop(), oldToNew, callStack, result.getStart());
+ return result;
+ }
+
+ @Override
+ public Set getAllContexts(Grammar grammar) {
+ Map> map = getOrCreate(grammar);
+ Set result = map.keySet();
+ return result;
+ }
+
+ protected EObject getContext(AbstractElement ele) {
+ if (ele instanceof RuleCall) {
+ if (GrammarUtil.isAssignedEObjectRuleCall(ele))
+ return ((RuleCall) ele).getRule();
+ } else if (GrammarUtil.isAssignedAction(ele))
+ return ele;
+ return null;
+ }
+
+ @Override
+ public Pda getContextPDA(Grammar grammar, EObject context) {
+ Map> map = getOrCreate(grammar);
+ Pda pda = map.get(context);
+ if (pda == null)
+ throw new IllegalStateException("Invlid context for serialization: " + context);
+ return pda;
+ }
+
+ protected Map> getOrCreate(Grammar grammar) {
+ Map> result = cache.get(grammar);
+ if (result != null)
+ return result;
+ result = Maps.newLinkedHashMap();
+ Set allParserRules = grammarPdaProvider.getAllRules(grammar);
+ Multimap> actionPdas = HashMultimap.create();
+ for (ParserRule rule : allParserRules) {
+ Pda pda = grammarPdaProvider.getGrammarPDA(grammar, rule);
+ List actions = Lists.newArrayList();
+ for (ISerState state : nfaUtil.collect(pda)) {
+ if (GrammarUtil.isAssignedAction(state.getGrammarElement())) {
+ actions.add(state);
+ }
+ }
+ if (actions.isEmpty()) {
+ result.put(rule, pda);
+ } else {
+ Pda rulePda = extract(pda.getStop());
+ result.put(rule, rulePda);
+ for (ISerState action : actions) {
+ Pda actionPda = extract(action);
+ actionPdas.put((Action) action.getGrammarElement(), actionPda);
+ }
+ }
+ }
+ for (Map.Entry>> action : actionPdas.asMap().entrySet()) {
+ Pda merged = merge(action.getValue());
+ result.put(action.getKey(), merged);
+ }
+ cache.put(grammar, result);
+ return result;
+ }
+
+ protected Pda merge(Collection> pdas) {
+ if (pdas.isEmpty())
+ throw new IllegalStateException();
+ if (pdas.size() == 1)
+ return pdas.iterator().next();
+ SerializerPDA merged = factory.create(null, null);
+ Map oldToNew = Maps.newHashMap();
+ for (Pda pda : pdas) {
+ oldToNew.put(pda.getStop(), merged.getStop());
+ merge(pda.getStart(), merged.getStart(), oldToNew, new IdentityHashMap());
+ }
+ return merged;
+ }
+
+ protected void merge(ISerState orig, SerializerPDAState copy, Map oldToNew,
+ IdentityHashMap visited) {
+ for (ISerState fol : orig.getFollowers()) {
+ SerializerPDAState folCopy = oldToNew.get(fol);
+ if (folCopy == null) {
+ folCopy = new SerializerPDAState(fol.getGrammarElement(), fol.getType());
+ oldToNew.put(fol, folCopy);
+ }
+ connect(copy, folCopy);
+ if (visited.put(fol, Boolean.TRUE) == null)
+ merge(fol, folCopy, oldToNew, visited);
+ }
+ }
+
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextProvider.java
index 6ed82d083..849518086 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextProvider.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextProvider.java
@@ -12,84 +12,34 @@ 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.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.ParserRule;
-import org.eclipse.xtext.serializer.analysis.TypeFinderNFAProvider.TypeFinderState;
-import org.eclipse.xtext.serializer.analysis.TypeFinderNFAProvider.TypeFinderTransition;
-import org.eclipse.xtext.util.EmfFormatter;
import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* @author Moritz Eysholdt - Initial contribution and API
+ *
+ * @deprecated see {@link IContextProvider} for documentation about this classes' replacements.
*/
@Singleton
+@Deprecated
public class ContextProvider implements IContextProvider {
@Inject
- protected TypeFinderNFAProvider nfaProvider2;
+ private IContextPDAProvider pdaProvider;
- protected void collectTypesForContext(TypeFinderState state, Set types, boolean allowLocal,
- boolean hasAssignment, Set visited) {
- hasAssignment = hasAssignment || state.getGrammarElement() instanceof Assignment || GrammarUtil.isEObjectFragmentRuleCall(state.getGrammarElement());
- if (allowLocal) {
- if (state.getGrammarElement() instanceof Action) {
- types.add((EClass) ((Action) state.getGrammarElement()).getType().getClassifier());
- return;
- }
- }
- if (state.isEndState() && !GrammarUtil.isUnassignedEObjectRuleCall(state.getGrammarElement())) {
- if (hasAssignment) {
- ParserRule rule = (ParserRule) GrammarUtil.containingRule(state.getGrammarElement());
- if (!rule.isFragment()) {
- types.add((EClass) rule.getType().getClassifier());
- }
- } else {
- types.add(null);
- }
- }
- if (!visited.add(state))
- return;
- for (TypeFinderTransition t : state.getAllOutgoing())
- if (!(t.isRuleCall() && state.getGrammarElement() instanceof Assignment))
- collectTypesForContext(t.getTarget(), types, true, hasAssignment, visited);
- }
+ @Inject
+ IContextTypePDAProvider typeProvider;
@Override
public List getAllContexts(Grammar grammar) {
- List result = Lists.newArrayList();
- for (ParserRule pr : GrammarUtil.allParserRules(grammar))
- if (GrammarUtil.isEObjectRule(pr)) {
- result.add(pr);
- for (Action action : GrammarUtil.containedActions(pr))
- if (GrammarUtil.isAssignedAction(action))
- result.add(action);
- }
- return result;
+ return Lists.newArrayList(pdaProvider.getAllContexts(grammar));
}
@Override
- public Set getTypesForContext(EObject context) {
- Set result = Sets.newHashSet();
- if (context instanceof AbstractElement) {
- AbstractElement ele = (AbstractElement) context;
- collectTypesForContext(nfaProvider2.getNFA(ele), result, false, false, Sets.newHashSet());
- } else if (context instanceof AbstractRule) {
- AbstractElement ele = ((AbstractRule) context).getAlternatives();
- collectTypesForContext(nfaProvider2.getNFA(ele), result, true, false, Sets.newHashSet());
- if (GrammarUtil.isOptionalCardinality(ele))
- result.add(null);
- } else
- throw new RuntimeException("This is not a valid context: " + EmfFormatter.objPath(context));
- return result;
+ public Set getTypesForContext(Grammar grammar, EObject context) {
+ return typeProvider.getTypesForContext(grammar, context);
}
-
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextTypePDAProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextTypePDAProvider.java
index 126672a95..b5d932bcf 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextTypePDAProvider.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ContextTypePDAProvider.java
@@ -7,24 +7,32 @@
*******************************************************************************/
package org.eclipse.xtext.serializer.analysis;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.Assignment;
+import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.TypeRef;
+import org.eclipse.xtext.serializer.analysis.ISerState.SerStateType;
import org.eclipse.xtext.serializer.analysis.SerializerPDA.SerializerPDACloneFactory;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.Tuples;
+import org.eclipse.xtext.util.Wrapper;
import org.eclipse.xtext.util.formallang.Pda;
import org.eclipse.xtext.util.formallang.PdaUtil;
import org.eclipse.xtext.util.formallang.Traverser;
+import com.google.common.base.Function;
import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -112,7 +120,7 @@ public class ContextTypePDAProvider implements IContextTypePDAProvider {
}
}
- protected static class TypeFilter implements Traverser, ISerState, FilterState> {
+ protected class TypeFilter implements Traverser, ISerState, FilterState> {
final protected EClass type;
public TypeFilter(EClass type) {
@@ -125,20 +133,11 @@ public class ContextTypePDAProvider implements IContextTypePDAProvider {
switch (state.getType()) {
case ELEMENT:
if (previous.type == null) {
- Assignment ass = GrammarUtil.containingAssignment(state.getGrammarElement());
- if (ass != null) {
- TypeRef returnType = GrammarUtil.containingRule(ass).getType();
- EClassifier cls = returnType != null ? returnType.getClassifier() : null;
- if (cls == type)
- return new FilterState(previous, type, previous.stack, state);
+ EClass cls = getInstantiatedType(state.getGrammarElement());
+ if (cls == type)
+ return new FilterState(previous, type, previous.stack, state);
+ if (cls != null)
return null;
- }
- if (state.getGrammarElement() instanceof Action) {
- EClassifier cls = ((Action) state.getGrammarElement()).getType().getClassifier();
- if (cls == type)
- return new FilterState(previous, type, previous.stack, state);
- return null;
- }
} else if (state.getGrammarElement() instanceof Action)
return null;
return new FilterState(previous, previous.type, previous.stack, state);
@@ -167,16 +166,17 @@ public class ContextTypePDAProvider implements IContextTypePDAProvider {
}
protected Map, Pda> cache = Maps.newHashMap();
- @Inject
- protected IContextProvider contextProvider;
@Inject
protected IContextPDAProvider pdaProvider;
- protected Pda createPDA(EObject context, EClass type) {
- Pda contextPda = pdaProvider.getContextPDA(context);
+ @Inject
+ protected PdaUtil pdaUtil;
+
+ protected Pda createPDA(Grammar grammar, EObject context, EClass type) {
+ Pda contextPda = pdaProvider.getContextPDA(grammar, context);
Pda contextTypePda = null;
- if (contextProvider.getTypesForContext(context).size() > 1) {
+ if (getTypesForContext(grammar, context).size() > 1) {
TypeFilter typeFilter = newTypeFilter(type);
SerializerPDACloneFactory factory = new SerializerPDACloneFactory();
contextTypePda = new PdaUtil().filterEdges(contextPda, typeFilter, factory);
@@ -186,11 +186,46 @@ public class ContextTypePDAProvider implements IContextTypePDAProvider {
}
@Override
- public Pda getContextTypePDA(EObject context, EClass type) {
+ public Pda getContextTypePDA(Grammar grammar, EObject context, EClass type) {
Pair key = Tuples.create(context, type);
Pda result = cache.get(key);
if (result == null)
- cache.put(key, result = createPDA(context, type));
+ cache.put(key, result = createPDA(grammar, context, type));
+ return result;
+ }
+
+ protected EClass getInstantiatedType(AbstractElement element) {
+ Assignment ass = GrammarUtil.containingAssignment(element);
+ TypeRef type = null;
+ if (ass != null) {
+ type = GrammarUtil.containingRule(ass).getType();
+ } else if (element instanceof Action) {
+ type = ((Action) element).getType();
+ }
+ if (type != null) {
+ EClassifier classifier = type.getClassifier();
+ if (classifier instanceof EClass && !classifier.eIsProxy()) {
+ return (EClass) classifier;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Set getTypesForContext(Grammar grammar, EObject context) {
+ Pda contextPda = pdaProvider.getContextPDA(grammar, context);
+ final Wrapper canReachStop = new Wrapper(false);
+ List list = pdaUtil.collectReachable(contextPda, new Function() {
+ @Override
+ public EClass apply(ISerState input) {
+ if (input.getType() == SerStateType.STOP)
+ canReachStop.set(true);
+ return getInstantiatedType(input.getGrammarElement());
+ }
+ });
+ Set result = Sets.newLinkedHashSet(list);
+ if (canReachStop.get())
+ result.add(null);
return result;
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/GrammarConstraintProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/GrammarConstraintProvider.java
index 703c58431..e1c0a0ee6 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/GrammarConstraintProvider.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/GrammarConstraintProvider.java
@@ -57,6 +57,7 @@ import com.google.inject.Singleton;
* @author Moritz Eysholdt - Initial contribution and API
*/
@Singleton
+@SuppressWarnings("deprecation")
public class GrammarConstraintProvider implements IGrammarConstraintProvider {
protected abstract static class AbstractConstraintContext implements IConstraintContext {
@@ -1442,7 +1443,7 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
AssignedActionConstraintContext result = new AssignedActionConstraintContext(context,
context2Name.getContextName(grammar, context));
ActionFilterState start = nfaProvider.getNFA(context);
- Set types = contextProvider.getTypesForContext(context);
+ Set types = contextProvider.getTypesForContext(grammar, context);
for (EClass type : types) {
if (type == null) {
Constraint constraint = new ActionConstraint(context, null, null, this);
@@ -1470,7 +1471,7 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
if (result == null) {
result = Lists.newArrayList();
for (ParserRule parserRule : GrammarUtil.allParserRules(context)) {
- if (parserRule.getType() != null && parserRule.getType().getClassifier() instanceof EClass) {
+ if (parserRule.getType() != null && parserRule.getType().getClassifier() instanceof EClass && !parserRule.isFragment()) {
result.add(getConstraints(context, parserRule));
for (Action action : GrammarUtil.containedActions(parserRule))
if (action.getFeature() != null)
@@ -1486,7 +1487,7 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
protected IConstraintContext getConstraints(Grammar grammar, ParserRule context) {
ParserRuleConstraintContext result = new ParserRuleConstraintContext(context,
context2Name.getContextName(grammar, context));
- Set types = contextProvider.getTypesForContext(context);
+ Set types = contextProvider.getTypesForContext(grammar, context);
for (EClass type : types) {
if (type == null) {
Constraint constraint = new RuleConstraint(context, null, null, this);
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/GrammarPDAProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/GrammarPDAProvider.java
new file mode 100644
index 000000000..c22ff5ab8
--- /dev/null
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/GrammarPDAProvider.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2011 itemis AG (http://www.itemis.eu) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.serializer.analysis;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.xtext.AbstractElement;
+import org.eclipse.xtext.Grammar;
+import org.eclipse.xtext.GrammarUtil;
+import org.eclipse.xtext.ParserRule;
+import org.eclipse.xtext.RuleCall;
+import org.eclipse.xtext.grammaranalysis.impl.CfgAdapter;
+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.PdaUtil;
+import org.eclipse.xtext.util.formallang.Production;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * @author Moritz Eysholdt - Initial contribution and API
+ */
+@Singleton
+public class GrammarPDAProvider implements IGrammarPDAProvider {
+
+ protected static class SerializerParserRuleCfg extends CfgAdapter {
+
+ private final ParserRule entryRule;
+
+ public SerializerParserRuleCfg(Grammar grammar, ParserRule entryRule) {
+ super(grammar);
+ this.entryRule = entryRule;
+ }
+
+ @Override
+ public AbstractElement getCall(AbstractElement ele) {
+ if (GrammarUtil.isEObjectRuleCall(ele) && !GrammarUtil.isAssigned(ele)) {
+ return ((RuleCall) ele).getRule().getAlternatives();
+ }
+ return null;
+ }
+
+ @Override
+ public AbstractElement getRoot() {
+ return entryRule.getAlternatives();
+ }
+
+ }
+
+ protected static class SerializerParserRuleFollowerFunction
+ extends FollowerFunctionImpl {
+
+ public SerializerParserRuleFollowerFunction(Production production) {
+ super(production);
+ }
+
+ }
+
+ protected Map> cache = Maps.newHashMap();
+
+ @Inject
+ protected PdaUtil pdaUtil;
+
+ protected Pda createPDA(Grammar grammar, ParserRule entryRule) {
+ Preconditions.checkArgument(isValidRule(entryRule));
+ SerializerParserRuleCfg cfg = new SerializerParserRuleCfg(grammar, entryRule);
+ SerializerParserRuleFollowerFunction ff = new SerializerParserRuleFollowerFunction(cfg);
+ Pda pda = pdaUtil.create(cfg, ff, new SerializerPDAElementFactory());
+ // return pdaUtil.filterOrphans(pda, new SerializerPDACloneFactory());
+ return pda;
+ }
+
+ @Override
+ public Pda getGrammarPDA(Grammar grammar, ParserRule entryRule) {
+ Pda result = cache.get(entryRule);
+ if (result == null)
+ cache.put(entryRule, result = createPDA(grammar, entryRule));
+ return result;
+ }
+
+ protected boolean isValidRule(ParserRule rule) {
+ return GrammarUtil.isEObjectRule(rule) && !rule.isFragment();
+ }
+
+ @Override
+ public Set getAllRules(Grammar grammar) {
+ Set result = Sets.newLinkedHashSet();
+ for (ParserRule rule : GrammarUtil.allParserRules(grammar))
+ if (isValidRule(rule))
+ result.add(rule);
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextPDAProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextPDAProvider.java
index 39a97700b..4139c6cf8 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextPDAProvider.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextPDAProvider.java
@@ -7,7 +7,10 @@
*******************************************************************************/
package org.eclipse.xtext.serializer.analysis;
+import java.util.Set;
+
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.util.formallang.Pda;
@@ -19,5 +22,7 @@ import com.google.inject.ImplementedBy;
@ImplementedBy(ContextPDAProvider.class)
public interface IContextPDAProvider {
- Pda getContextPDA(EObject context);
+ Pda getContextPDA(Grammar grammar, EObject context);
+
+ Set getAllContexts(Grammar grammar);
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextProvider.java
index ded987344..1ebdb4686 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextProvider.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextProvider.java
@@ -18,10 +18,21 @@ import com.google.inject.ImplementedBy;
/**
* @author Moritz Eysholdt - Initial contribution and API
+ * @deprecated see methods of this class for documentation about their replacements
*/
+@Deprecated
@ImplementedBy(ContextProvider.class)
public interface IContextProvider {
+
+ /**
+ * @deprecated use {@link IContextPDAProvider#getAllContexts(Grammar)}
+ */
+ @Deprecated
public List getAllContexts(Grammar grammar);
- public Set getTypesForContext(EObject context);
+ /**
+ * @deprecated use {@link IContextTypePDAProvider#getTypesForContext(Grammar, EObject)}
+ */
+ @Deprecated
+ public Set getTypesForContext(Grammar grammar, EObject context);
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextTypePDAProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextTypePDAProvider.java
index f5721b53d..64878a5d6 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextTypePDAProvider.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IContextTypePDAProvider.java
@@ -7,8 +7,11 @@
*******************************************************************************/
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.Grammar;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.util.formallang.Pda;
@@ -20,5 +23,7 @@ import com.google.inject.ImplementedBy;
@ImplementedBy(ContextTypePDAProvider.class)
public interface IContextTypePDAProvider {
- Pda getContextTypePDA(EObject context, EClass type);
+ Pda getContextTypePDA(Grammar grammar, EObject context, EClass type);
+
+ public Set getTypesForContext(Grammar grammar, EObject context);
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IGrammarPDAProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IGrammarPDAProvider.java
new file mode 100644
index 000000000..3f812524e
--- /dev/null
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/IGrammarPDAProvider.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2011 itemis AG (http://www.itemis.eu) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.serializer.analysis;
+
+import java.util.Set;
+
+import org.eclipse.xtext.Grammar;
+import org.eclipse.xtext.ParserRule;
+import org.eclipse.xtext.RuleCall;
+import org.eclipse.xtext.util.formallang.Pda;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * @author Moritz Eysholdt - Initial contribution and API
+ */
+@ImplementedBy(GrammarPDAProvider.class)
+public interface IGrammarPDAProvider {
+
+ Pda getGrammarPDA(Grammar grammar, ParserRule entryRule);
+
+ Set getAllRules(Grammar grammar);
+}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ISerState.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ISerState.java
index d6e06b9c4..295b2479b 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ISerState.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/ISerState.java
@@ -16,8 +16,12 @@ public interface ISerState {
ELEMENT, POP, PUSH, START, STOP;
}
+ // ISerState getOpposite();
+
List extends ISerState> getFollowers();
+ List extends ISerState> getPrecedents();
+
AbstractElement getGrammarElement();
SerStateType getType();
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/SerializerPDA.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/SerializerPDA.java
index 3662644e7..fdf4df05e 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/SerializerPDA.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/SerializerPDA.java
@@ -7,10 +7,10 @@
*******************************************************************************/
package org.eclipse.xtext.serializer.analysis;
-import java.util.Collections;
import java.util.List;
import org.eclipse.xtext.AbstractElement;
+import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
import org.eclipse.xtext.serializer.analysis.ISerState.SerStateType;
@@ -20,6 +20,7 @@ import org.eclipse.xtext.util.formallang.Pda;
import org.eclipse.xtext.util.formallang.PdaFactory;
import com.google.common.base.Function;
+import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
public class SerializerPDA implements Pda {
@@ -54,8 +55,8 @@ public class SerializerPDA implements Pda {
}
}
- public static class SerializerPDAElementFactory implements
- PdaFactory {
+ public static class SerializerPDAElementFactory
+ implements PdaFactory {
@Override
public SerializerPDA create(AbstractElement start, AbstractElement stop) {
@@ -82,6 +83,9 @@ public class SerializerPDA implements Pda {
@Override
public void setFollowers(SerializerPDA nfa, ISerState owner, Iterable followers) {
((SerializerPDA.SerializerPDAState) owner).followers = Lists.newArrayList(followers);
+ for (ISerState follower : followers) {
+ ((SerializerPDA.SerializerPDAState) follower).precedents.add(owner);
+ }
}
}
@@ -94,10 +98,21 @@ public class SerializerPDA implements Pda {
}
+ public static class SerializerPDAIsAssignedAction implements Predicate {
+
+ @Override
+ public boolean apply(ISerState input) {
+ return input != null && GrammarUtil.isAssignedAction(input.getGrammarElement());
+ }
+
+ }
+
protected static class SerializerPDAState implements ISerState {
- protected List followers = Collections.emptyList();
- protected AbstractElement grammarElement;
- protected SerStateType type;
+ protected List followers = Lists.newArrayList();
+ protected final List precedents = Lists.newArrayList();
+ protected final AbstractElement grammarElement;
+ protected final SerStateType type;
+ // protected final SerializerPDAState opposite;
public SerializerPDAState(AbstractElement grammarElement, SerStateType type) {
super();
@@ -151,6 +166,16 @@ public class SerializerPDA implements Pda {
}
return "";
}
+
+ @Override
+ public List getPrecedents() {
+ return precedents;
+ }
+
+ // @Override
+ // public ISerState getOpposite() {
+ // return null;
+ // }
}
protected SerializerPDA.SerializerPDAState start;
@@ -187,12 +212,12 @@ public class SerializerPDA implements Pda {
}
@Override
- public ISerState getStart() {
+ public SerializerPDAState getStart() {
return start;
}
@Override
- public ISerState getStop() {
+ public SerializerPDAState getStop() {
return stop;
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/SyntacticSequencerPDAProvider.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/SyntacticSequencerPDAProvider.java
index abbff3f01..aaf56b7da 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/SyntacticSequencerPDAProvider.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis/SyntacticSequencerPDAProvider.java
@@ -20,6 +20,7 @@ import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.EnumRule;
+import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.ParserRule;
@@ -612,7 +613,8 @@ public class SyntacticSequencerPDAProvider implements ISyntacticSequencerPDAProv
if (result == null) {
Map absorbers = Maps.newHashMap();
Map> emitters = Maps.newHashMap();
- Pda extends ISerState, RuleCall> pda = pdaProvider.getContextTypePDA(context, type);
+ Grammar grammar = GrammarUtil.getGrammar(context);
+ Pda extends ISerState, RuleCall> pda = pdaProvider.getContextTypePDA(grammar, context, type);
result = createAbsorberState(pda.getStart(), absorbers, emitters, context, type);
cache.put(key, result);
}
diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/AbstractSemanticSequencerTest.java b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/AbstractSemanticSequencerTest.java
index cc360f300..2ed0ab55c 100644
--- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/AbstractSemanticSequencerTest.java
+++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/AbstractSemanticSequencerTest.java
@@ -561,5 +561,11 @@ public abstract class AbstractSemanticSequencerTest extends AbstractXtextTests {
EObject model = testSequence("#32 null");
Assert.assertNull(((NullCrossRef) model).getRef());
}
+
+ @Test
+ public void testFragment() throws Exception {
+ testSequence("#33 foo bar baz");
+ }
-}
\ No newline at end of file
+
+}
diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextPDAProviderTest.java b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextPDAProviderTest.java
index 2564a417e..1d4b953aa 100644
--- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextPDAProviderTest.java
+++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextPDAProviderTest.java
@@ -20,13 +20,11 @@ import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
import org.eclipse.xtext.junit4.AbstractXtextTests;
import org.eclipse.xtext.serializer.analysis.Context2NameFunction;
import org.eclipse.xtext.serializer.analysis.IContextPDAProvider;
-import org.eclipse.xtext.serializer.analysis.IContextProvider;
import org.eclipse.xtext.serializer.analysis.ISerState;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.Tuples;
import org.eclipse.xtext.util.formallang.Pda;
import org.eclipse.xtext.util.formallang.PdaListFormatter;
-import org.junit.Ignore;
import org.junit.Test;
import com.google.common.base.Function;
@@ -60,7 +58,7 @@ public class ContextPDAProviderTest extends AbstractXtextTests {
private List> getContexts(Grammar grammar) {
final Context2NameFunction ctx2name = get(Context2NameFunction.class);
- final IContextProvider contextProvider = get(IContextProvider.class);
+ final IContextPDAProvider contextProvider = get(IContextPDAProvider.class);
List> result = Lists.newArrayList();
for (EObject ctx : contextProvider.getAllContexts(grammar))
result.add(Tuples.create(ctx, ctx2name.getContextName(grammar, ctx)));
@@ -81,13 +79,15 @@ public class ContextPDAProviderTest extends AbstractXtextTests {
formatter.setStackitemFormatter(new GrammarElementTitleSwitch().showAssignments().hideCardinality());
formatter.sortFollowers();
IContextPDAProvider pdaProvider = get(IContextPDAProvider.class);
- for (Pair ctx : getContexts(grammar)) {
+ List> contexts = getContexts(grammar);
+ for (Pair ctx : contexts) {
result.add(ctx.getSecond() + ":");
- Pda pda = pdaProvider.getContextPDA(ctx.getFirst());
+ Pda pda = pdaProvider.getContextPDA(grammar, ctx.getFirst());
result.add(" " + formatter.format(pda).replace("\n", "\n "));
- // StackTraceElement ele = Thread.currentThread().getStackTrace()[2];
- // String name = getClass().getSimpleName() + "_" + ele.getMethodName() + "_" + ctx.getSecond() + ".pdf";
- // new PdaToDot().draw(pda, name, "-T pdf");
+
+ // StackTraceElement ele = Thread.currentThread().getStackTrace()[2];
+ // String name = getClass().getSimpleName() + "_" + ele.getMethodName() + "_" + ctx.getSecond() + ".pdf";
+ // new PdaToDot().draw(pda, "dot/" + name, "-T pdf");
}
return Joiner.on("\n").join(result);
}
@@ -97,61 +97,83 @@ public class ContextPDAProviderTest extends AbstractXtextTests {
super.setUp();
with(XtextStandaloneSetup.class);
}
-
+
@Test
- @Ignore("TODO implement me, expectation is not correct so far")
public void testFragmentWithAction() throws Exception {
- String actual = getParserRule("R: f1=ID F; fragment F returns R: {A.prev=current} f2=ID;");
+ String actual = getParserRule("R: 'kw1' F; fragment F returns R: f1=ID {A.prev=current} f2=ID;");
StringBuilder expected = new StringBuilder();
- expected.append("Rule:\n");
- expected.append(" start -> {Act.val2=}\n");
- expected.append(" val3=ID -> stop\n");
- expected.append(" {Act.val2=} -> val3=ID\n");
- expected.append("Rule_Act_1:\n");
- expected.append(" start -> val1=ID\n");
- expected.append(" val1=ID -> stop");
+ expected.append("F_A_1:\n");
+ expected.append(" start -> f1=ID\n");
+ expected.append(" f1=ID -> stop\n");
+ expected.append("R:\n");
+ expected.append(" start -> 'kw1'\n");
+ expected.append(" 'kw1' -> >>F\n");
+ expected.append(" < stop\n");
+ expected.append(" >>F -> {A.prev=}\n");
+ expected.append(" f2=ID -> < f2=ID");
assertEquals(expected.toString(), actual);
}
-
+
@Test
- @Ignore("TODO implement me, expectation is not correct so far")
public void testFragmentWithActionRecursive() throws Exception {
- String actual = getParserRule("R: f1=ID F; fragment F returns R: {A.prev=current} f2=ID F?;");
+ String actual = getParserRule("R: 'kw1' F; fragment F returns R: 'kw2' F? f1=ID {A.prev=current} f2=ID;");
StringBuilder expected = new StringBuilder();
- expected.append("Rule:\n");
- expected.append(" start -> a1=ID\n");
- expected.append(" 'kw1' -> a2=ID\n");
- expected.append(" 'kw2' -> a2=ID\n");
- expected.append(" a1=ID -> 'kw1', 'kw2'\n");
- expected.append(" a2=ID -> stop");
+ expected.append("F_A_3:\n");
+ expected.append(" start -> 'kw2'\n");
+ expected.append(" 'kw2' -> >>F, f1=ID\n");
+ expected.append(" < f1=ID\n");
+ expected.append(" >>F -> {A.prev=}\n");
+ expected.append(" f1=ID -> stop\n");
+ expected.append(" f2=ID -> < f2=ID\n");
+ expected.append("R:\n");
+ expected.append(" start -> 'kw1'\n");
+ expected.append(" 'kw1' -> >>F\n");
+ expected.append(" < stop\n");
+ expected.append(" >>F -> {A.prev=}\n");
+ expected.append(" f2=ID -> < f2=ID");
assertEquals(expected.toString(), actual);
}
-
+
@Test
- @Ignore("TODO implement me, expectation is not correct so far")
public void testFragmentWithActionTwice() throws Exception {
- String actual = getParserRule("R: f1=ID F; fragment F returns R: {A.prev=current} f2=ID {A.prev=current} f2=ID;");
+ String g = "R: 'kw1' F; fragment F returns R: f1=ID {A.prev=current} f2=ID {B.prev=current} f3=ID;";
+ String actual = getParserRule(g);
StringBuilder expected = new StringBuilder();
- expected.append("Rule:\n");
- expected.append(" start -> a1=ID\n");
- expected.append(" 'kw1' -> a2=ID\n");
- expected.append(" 'kw2' -> a2=ID\n");
- expected.append(" a1=ID -> 'kw1', 'kw2'\n");
- expected.append(" a2=ID -> stop");
+ expected.append("F_A_1:\n");
+ expected.append(" start -> f1=ID\n");
+ expected.append(" f1=ID -> stop\n");
+ expected.append("F_B_3:\n");
+ expected.append(" start -> {A.prev=}\n");
+ expected.append(" f2=ID -> stop\n");
+ expected.append(" {A.prev=} -> f2=ID\n");
+ expected.append("R:\n");
+ expected.append(" start -> 'kw1'\n");
+ expected.append(" 'kw1' -> >>F\n");
+ expected.append(" < stop\n");
+ expected.append(" >>F -> {B.prev=}\n");
+ expected.append(" f3=ID -> < f3=ID");
assertEquals(expected.toString(), actual);
}
-
+
@Test
- @Ignore("TODO implement me, expectation is not correct so far")
public void testFragmentWithActionLoop() throws Exception {
String actual = getParserRule("R: f1=ID F; fragment F returns R: ({A.prev=current} f2=ID)*;");
StringBuilder expected = new StringBuilder();
- expected.append("Rule:\n");
- expected.append(" start -> a1=ID\n");
- expected.append(" 'kw1' -> a2=ID\n");
- expected.append(" 'kw2' -> a2=ID\n");
- expected.append(" a1=ID -> 'kw1', 'kw2'\n");
- expected.append(" a2=ID -> stop");
+ expected.append("F_A_0:\n");
+ expected.append(" start -> stop, {A.prev=}\n");
+ expected.append(" f2=ID -> stop\n");
+ expected.append(" {A.prev=} -> f2=ID\n");
+ expected.append("R:\n");
+ expected.append(" start -> f1=ID\n");
+ expected.append(" < stop\n");
+ expected.append(" >>F -> < >>F\n");
+ expected.append(" f2=ID -> < f2=ID");
assertEquals(expected.toString(), actual);
}
@@ -168,6 +190,34 @@ public class ContextPDAProviderTest extends AbstractXtextTests {
assertEquals(expected.toString(), actual);
}
+ @Test
+ public void testAssignedEObjectRuleCall() throws Exception {
+ String actual = getParserRule("Rule: foo=Sub; Sub: id='id';");
+ StringBuilder expected = new StringBuilder();
+ expected.append("Rule:\n");
+ expected.append(" start -> foo=Sub\n");
+ expected.append(" foo=Sub -> stop\n");
+ expected.append("Sub:\n");
+ expected.append(" start -> id='id'\n");
+ expected.append(" id='id' -> stop");
+ assertEquals(expected.toString(), actual);
+ }
+
+ @Test
+ public void testTwoAssignedEObjectRuleCalls() throws Exception {
+ String actual = getParserRule("Rule: foo1=Sub 'x' foo2=Sub; Sub: id='id';");
+ StringBuilder expected = new StringBuilder();
+ expected.append("Rule:\n");
+ expected.append(" start -> foo1=Sub\n");
+ expected.append(" 'x' -> foo2=Sub\n");
+ expected.append(" foo1=Sub -> 'x'\n");
+ expected.append(" foo2=Sub -> stop\n");
+ expected.append("Sub:\n");
+ expected.append(" start -> id='id'\n");
+ expected.append(" id='id' -> stop");
+ assertEquals(expected.toString(), actual);
+ }
+
@Test
public void testDelegation1() throws Exception {
String actual = getParserRule("Rule: Delegate; Delegate: val=ID;");
@@ -185,7 +235,8 @@ public class ContextPDAProviderTest extends AbstractXtextTests {
@Test
public void testDelegation2() throws Exception {
- String actual = getParserRule("Rule: Foo | Delegate1; Delegate1: 'del' Delegate2 bar=ID; Delegate2: val=ID; Foo: val2=ID;");
+ String actual = getParserRule(
+ "Rule: Foo | Delegate1; Delegate1: 'del' Delegate2 bar=ID; Delegate2: val=ID; Foo: val2=ID;");
StringBuilder expected = new StringBuilder();
expected.append("Delegate1:\n");
expected.append(" start -> 'del'\n");
@@ -277,6 +328,35 @@ public class ContextPDAProviderTest extends AbstractXtextTests {
assertEquals(expected.toString(), actual);
}
+ @Test
+ public void testDualDelegation() throws Exception {
+ StringBuilder grammar = new StringBuilder();
+ grammar.append("Model: foo=AbstractRule;\n");
+ grammar.append("AbstractRule: Rule1 | Rule2;\n");
+ grammar.append("Rule1: foo1=ID;\n");
+ grammar.append("Rule2: foo2=ID;\n");
+ String actual = getParserRule(grammar.toString());
+ StringBuilder expected = new StringBuilder();
+ expected.append("AbstractRule:\n");
+ expected.append(" start -> >>Rule1, >>Rule2\n");
+ expected.append(" < stop\n");
+ expected.append(" < stop\n");
+ expected.append(" >>Rule1 -> foo1=ID\n");
+ expected.append(" >>Rule2 -> foo2=ID\n");
+ expected.append(" foo1=ID -> < < foo=AbstractRule\n");
+ expected.append(" foo=AbstractRule -> stop\n");
+ expected.append("Rule1:\n");
+ expected.append(" start -> foo1=ID\n");
+ expected.append(" foo1=ID -> stop\n");
+ expected.append("Rule2:\n");
+ expected.append(" start -> foo2=ID\n");
+ expected.append(" foo2=ID -> stop");
+ assertEquals(expected.toString(), actual);
+ }
+
@Test
public void testOptionalEnd() throws Exception {
StringBuilder grammar = new StringBuilder();
@@ -358,7 +438,8 @@ public class ContextPDAProviderTest extends AbstractXtextTests {
@Test
public void testExpression1() throws Exception {
- String actual = getParserRule("Exp: 'kw' Addit; Addit returns Exp: Prim ({Add.left=current} '+' right=Prim)*; Prim returns Exp: {Val} val=ID;");
+ String actual = getParserRule(
+ "Exp: 'kw' Addit; Addit returns Exp: Prim ({Add.left=current} '+' right=Prim)*; Prim returns Exp: {Val} val=ID;");
StringBuilder expected = new StringBuilder();
expected.append("Addit:\n");
expected.append(" start -> >>Prim, {Add.left=}\n");
diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextProviderTest.java b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextProviderTest.java
index 6fa5e98d9..9de8ac35a 100644
--- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextProviderTest.java
+++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextProviderTest.java
@@ -17,7 +17,8 @@ import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.XtextStandaloneSetup;
import org.eclipse.xtext.junit4.AbstractXtextTests;
import org.eclipse.xtext.serializer.analysis.Context2NameFunction;
-import org.eclipse.xtext.serializer.analysis.IContextProvider;
+import org.eclipse.xtext.serializer.analysis.IContextPDAProvider;
+import org.eclipse.xtext.serializer.analysis.IContextTypePDAProvider;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.Tuples;
import org.junit.Ignore;
@@ -44,12 +45,13 @@ public class ContextProviderTest extends AbstractXtextTests {
protected String getContexts(String body) throws Exception {
Grammar grammar = (Grammar) getModel(HEADER + body);
- IContextProvider contextProvider = get(IContextProvider.class);
+ IContextPDAProvider contextProvider = get(IContextPDAProvider.class);
+ IContextTypePDAProvider typeProvider = get(IContextTypePDAProvider.class);
Context2NameFunction names = get(Context2NameFunction.class);
List>> result = Lists.newArrayList();
for (EObject context : contextProvider.getAllContexts(grammar)) {
List types = Lists.newArrayList();
- for (EClass type : contextProvider.getTypesForContext(context))
+ for (EClass type : typeProvider.getTypesForContext(grammar, context))
types.add(type == null ? "null" : type.getName());
Collections.sort(types);
result.add(Tuples.create(names.getContextName(grammar, context), types));
@@ -74,52 +76,50 @@ public class ContextProviderTest extends AbstractXtextTests {
String expected = "Rule returns Rule";
assertEquals(expected, actual);
}
-
+
@Test
@Ignore("TODO implement in context provider")
public void testFragmentIsNotAContext() throws Exception {
- String actual = getContexts("Rule: foo=ID; fragment Fragment: name=ID WCFragment; fragment WCFragment*: desc=STRING;");
+ String actual = getContexts(
+ "Rule: foo=ID; fragment Fragment: name=ID WCFragment; fragment WCFragment*: desc=STRING;");
String expected = "Rule returns Rule";
assertEquals(expected, actual);
}
-
+
@Test
@Ignore("TODO implement in context provider")
public void testActionInFragment() throws Exception {
- String actual = getContexts("Rule: foo=ID Fragment; fragment Fragment returns AbstractRule: {AnotherRule.prev=current} name=ID;");
- String expected = "Fragment_AnotherRule_0 returns Rule\n" +
- "Rule returns AnotherRule";
+ String actual = getContexts(
+ "Rule: foo=ID Fragment; fragment Fragment returns AbstractRule: {AnotherRule.prev=current} name=ID;");
+ String expected = "Fragment_AnotherRule_0 returns Rule\n" + "Rule returns AnotherRule";
assertEquals(expected, actual);
}
-
+
@Test
@Ignore("TODO implement in context provider")
public void testTwoActionsInFragment() throws Exception {
- String actual = getContexts("Rule0: f1=ID Fragment; fragment Fragment returns Rule: {Rule1.prev=current} f2=ID {Rule2.prev=current} f3=ID;");
- String expected = "Fragment_Rule1_0 returns Rule0\n" +
- "Fragment_Rule2_2 returns Rule1\n" +
- "Rule0 returns Rule2";
+ String actual = getContexts(
+ "Rule0: f1=ID Fragment; fragment Fragment returns Rule: {Rule1.prev=current} f2=ID {Rule2.prev=current} f3=ID;");
+ String expected = "Fragment_Rule1_0 returns Rule0\n" + "Fragment_Rule2_2 returns Rule1\n"
+ + "Rule0 returns Rule2";
assertEquals(expected, actual);
}
-
+
@Test
@Ignore("TODO implement in context provider")
public void testActionsInFragmentTwoCallers() throws Exception {
String actual = getContexts(
"Rule0: f1=ID Fragment; Rule1: f2=ID Fragment; fragment Fragment returns Rule: {Rule2.prev=current} f3=ID;");
- String expected = "Fragment_Rule2_0 returns Rule0, Rule1\n" +
- "Rule0 returns Rule2\n" +
- "Rule1 returns Rule2";
+ String expected = "Fragment_Rule2_0 returns Rule0, Rule1\n" + "Rule0 returns Rule2\n" + "Rule1 returns Rule2";
assertEquals(expected, actual);
}
-
+
@Test
@Ignore("TODO implement in context provider")
public void testActionsInFragmentTwoPrecedingActions() throws Exception {
String actual = getContexts(
"Rule0: ({Rule1} f1=ID | {Rule2} f1=STRING) Fragment?; fragment Fragment returns Rule: {Rule3.prev=current} f3=ID;");
- String expected = "Fragment_Rule3_0 returns Rule1, Rule2\n" +
- "Rule0 returns Rule1, Rule2, Rule3";
+ String expected = "Fragment_Rule3_0 returns Rule1, Rule2\n" + "Rule0 returns Rule1, Rule2, Rule3";
assertEquals(expected, actual);
}
diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextTypePDAProviderTest.java b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextTypePDAProviderTest.java
index de7c698dd..c5fa4936b 100644
--- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextTypePDAProviderTest.java
+++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/ContextTypePDAProviderTest.java
@@ -20,7 +20,7 @@ import org.eclipse.xtext.XtextStandaloneSetup;
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
import org.eclipse.xtext.junit4.AbstractXtextTests;
import org.eclipse.xtext.serializer.analysis.Context2NameFunction;
-import org.eclipse.xtext.serializer.analysis.IContextProvider;
+import org.eclipse.xtext.serializer.analysis.IContextPDAProvider;
import org.eclipse.xtext.serializer.analysis.IContextTypePDAProvider;
import org.eclipse.xtext.serializer.analysis.ISerState;
import org.eclipse.xtext.util.Triple;
@@ -60,10 +60,11 @@ public class ContextTypePDAProviderTest extends AbstractXtextTests {
private List> getContexts(Grammar grammar) {
final Context2NameFunction ctx2name = get(Context2NameFunction.class);
- final IContextProvider contextProvider = get(IContextProvider.class);
+ final IContextPDAProvider contextProvider = get(IContextPDAProvider.class);
+ final IContextTypePDAProvider typeProvider = get(IContextTypePDAProvider.class);
List> result = Lists.newArrayList();
for (EObject ctx : contextProvider.getAllContexts(grammar))
- for (EClass type : contextProvider.getTypesForContext(ctx))
+ for (EClass type : typeProvider.getTypesForContext(grammar, ctx))
result.add(Tuples.create(type, ctx, ctx2name.getContextName(grammar, ctx)));
Collections.sort(result, new Comparator>() {
@Override
@@ -93,7 +94,7 @@ public class ContextTypePDAProviderTest extends AbstractXtextTests {
String t = ctx.getFirst() == null ? "null" : ctx.getFirst().getName();
// System.out.println(t + "_" + ctx.getThird() + ":");
result.add(t + "_" + ctx.getThird() + ":");
- Pda extends ISerState, RuleCall> pda = get(IContextTypePDAProvider.class).getContextTypePDA(
+ Pda extends ISerState, RuleCall> pda = get(IContextTypePDAProvider.class).getContextTypePDA(grammar,
ctx.getSecond(), ctx.getFirst());
result.add(" " + formatter.format((Pda) pda).replace("\n", "\n "));
}
@@ -371,4 +372,25 @@ public class ContextTypePDAProviderTest extends AbstractXtextTests {
expected.append(" {Model} -> 'kw1'");
assertEquals(expected.toString(), actual);
}
+
+ @Test
+ public void testUnorderedGroup() throws Exception {
+ StringBuilder grammar = new StringBuilder();
+ grammar.append("Model: 'model' '{' (greetings1+=ID+ & greetings2+=ID*) '}';");
+ String actual = getParserRule(grammar.toString());
+ StringBuilder expected = new StringBuilder();
+ expected.append("Model_Model:\n");
+ expected.append(" start -> 'model'\n");
+ expected.append(" 'model' -> '{'\n");
+ expected.append(" '{' -> greetings1+=ID, greetings2+=ID\n");
+ expected.append(" '}' -> stop\n");
+ expected.append(" greetings1+=ID -> '}', greetings1+=ID, greetings2+=ID\n");
+ expected.append(" greetings2+=ID -> '}', greetings1+=ID, greetings2+=ID\n");
+ expected.append("null_Model:\n");
+ expected.append(" start -> 'model'\n");
+ expected.append(" 'model' -> '{'\n");
+ expected.append(" '{' -> '}'\n");
+ expected.append(" '}' -> stop");
+ assertEquals(expected.toString(), actual);
+ }
}
diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/GrammarPDAProviderTest.xtend b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/GrammarPDAProviderTest.xtend
new file mode 100644
index 000000000..274a05086
--- /dev/null
+++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/GrammarPDAProviderTest.xtend
@@ -0,0 +1,432 @@
+/*******************************************************************************
+ * Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.serializer
+
+import com.google.inject.Inject
+import org.eclipse.xtext.Grammar
+import org.eclipse.xtext.RuleCall
+import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch
+import org.eclipse.xtext.junit4.InjectWith
+import org.eclipse.xtext.junit4.XtextRunner
+import org.eclipse.xtext.junit4.internal.XtextInjectorProvider
+import org.eclipse.xtext.junit4.util.ParseHelper
+import org.eclipse.xtext.junit4.validation.ValidationTestHelper
+import org.eclipse.xtext.serializer.analysis.IGrammarPDAProvider
+import org.eclipse.xtext.serializer.analysis.ISerState
+import org.eclipse.xtext.util.formallang.Pda
+import org.eclipse.xtext.util.formallang.PdaListFormatter
+import org.eclipse.xtext.util.formallang.PdaToDot
+import org.junit.Assert
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * @author Moritz Eysholdt - Initial contribution and API
+ */
+@RunWith(XtextRunner)
+@InjectWith(XtextInjectorProvider)
+class GrammarPDAProviderTest {
+
+ @Inject IGrammarPDAProvider pdaProvider
+ @Inject ParseHelper parser
+ @Inject ValidationTestHelper validator
+
+ @Test def void testUnassignedAction() {
+ val actual = '''
+ Rule: {Action};
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> {Action}
+ {Action} -> stop
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testAssignedAction() {
+ val actual = '''
+ Rule: {Foo} {Action.feat=current};
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> {Foo}
+ {Action.feat=} -> stop
+ {Foo} -> {Action.feat=}
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testAssignedTerminalRuleCall() {
+ val actual = '''
+ Rule: name=ID;
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> name=ID
+ name=ID -> stop
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testAssignedEObjectRuleCall() {
+ val actual = '''
+ Rule: call=Called;
+ Called: name=ID;
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> call=Called
+ call=Called -> stop
+ Called:
+ start -> name=ID
+ name=ID -> stop
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testAssignedDatatypeRuleCall() {
+ val actual = '''
+ Rule: call=Called;
+ Called: "foo";
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> call=Called
+ call=Called -> stop
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testUnassignedCalledAction() {
+ val actual = '''
+ Rule: D1 | D2;
+ D1: 'd1' A;
+ D2: 'd2' A;
+ A: f1=ID {A.l=current} f2=ID;
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> >>D1, >>D2
+ 'd1' -> >>A
+ 'd2' -> >>A
+ < < < stop
+ < stop
+ >>A -> f1=ID
+ >>A -> f1=ID
+ >>D1 -> 'd1'
+ >>D2 -> 'd2'
+ f1=ID -> {A.l=}
+ f2=ID -> < f2=ID
+ D1:
+ start -> 'd1'
+ 'd1' -> >>A
+ < stop
+ >>A -> f1=ID
+ f1=ID -> {A.l=}
+ f2=ID -> < f2=ID
+ D2:
+ start -> 'd2'
+ 'd2' -> >>A
+ < stop
+ >>A -> f1=ID
+ f1=ID -> {A.l=}
+ f2=ID -> < f2=ID
+ A:
+ start -> f1=ID
+ f1=ID -> {A.l=}
+ f2=ID -> stop
+ {A.l=} -> f2=ID
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testUnassignedFragmentRuleCall() {
+ val actual = '''
+ Rule: Called;
+ fragment Called returns Abstract: name=ID;
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> >>Called
+ < stop
+ >>Called -> name=ID
+ name=ID -> < >>Called
+ < stop
+ >>Called -> name=ID
+ name=ID -> < name=ID
+ name=ID -> stop
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testUnassignedWildcardFragmentRuleCall() {
+ val actual = '''
+ Rule: Called;
+ fragment Called*: name=ID;
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> >>Called
+ < stop
+ >>Called -> name=ID
+ name=ID -> < {Rule}
+ 'a' -> 'b'
+ 'b' -> 'c'
+ 'c' -> stop
+ {Rule} -> 'a'
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testAlternative() {
+ val actual = '''
+ Rule: {Rule} ('a' | 'b' | 'c');
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> {Rule}
+ 'a' -> stop
+ 'b' -> stop
+ 'c' -> stop
+ {Rule} -> 'a', 'b', 'c'
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testUnorderedGroup() {
+ val actual = '''
+ Rule: {Rule} ('a' & 'b' & 'c');
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> {Rule}
+ 'a' -> 'a', 'b', 'c', stop
+ 'b' -> 'a', 'b', 'c', stop
+ 'c' -> 'a', 'b', 'c', stop
+ {Rule} -> 'a', 'b', 'c'
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testUnorderedGroup2() {
+ val actual = '''
+ Rule: {Rule} ('a' & 'b'? & 'c'* & 'd'+);
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> {Rule}
+ 'a' -> 'a', 'b', 'c', 'd', stop
+ 'b' -> 'a', 'b', 'c', 'd', stop
+ 'c' -> 'a', 'b', 'c', 'd', stop
+ 'd' -> 'a', 'b', 'c', 'd', stop
+ {Rule} -> 'a', 'b', 'c', 'd'
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testTwoAssignedEObjectRuleCalls() {
+ val actual = '''
+ Rule: foo1=Sub foo2=Sub; Sub: id='id';
+ '''.toPda
+ val expected = '''
+ Rule:
+ start -> foo1=Sub
+ foo1=Sub -> foo2=Sub
+ foo2=Sub -> stop
+ Sub:
+ start -> id='id'
+ id='id' -> stop
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testRecursion() {
+ val actual = '''
+ Recursion: val=ID | '(' Recursion ')';
+ '''.toPda
+ val expected = '''
+ Recursion:
+ start -> '(', val=ID
+ '(' -> >>Recursion
+ ')' -> < ')'
+ >>Recursion -> '(', val=ID
+ val=ID -> < 'kw'
+ '+' -> right=Prim
+ 'kw' -> >>Addit
+ < stop
+ < <>Addit -> >>Prim
+ >>Prim -> {Val}
+ right=Prim -> < < '+'
+ {Val} -> val=ID
+ Addit:
+ start -> >>Prim
+ '+' -> right=Prim
+ < stop, {Add.left=}
+ >>Prim -> {Val}
+ right=Prim -> stop, {Add.left=}
+ val=ID -> < '+'
+ {Val} -> val=ID
+ Prim:
+ start -> {Val}
+ val=ID -> stop
+ {Val} -> val=ID
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test def void testActionAlternative() {
+ val actual = '''
+ Greeting: '(' Greeting ')' {Foo.child=current} | val=ID;
+ '''.toPda
+ val expected = '''
+ Greeting:
+ start -> '(', val=ID
+ '(' -> >>Greeting
+ ')' -> {Foo.child=}
+ < ')'
+ >>Greeting -> '(', val=ID
+ val=ID -> < < f1=ID
+ < stop
+ >>F -> {A.prev=}
+ f1=ID -> >>F
+ f2=ID -> < f2=ID
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test @Ignore def void testFragmentWithAction2() {
+ val actual = '''
+ R: 'kw1a' f1=ID 'kw1b' F; fragment F returns R: 'kw2a' {A.prev=current} 'kw2b' f2=ID 'kw2c';
+ '''.toPda
+ val expected = '''
+ R:
+ start -> f1=ID
+ < stop
+ >>F -> {A.prev=}
+ f1=ID -> >>F
+ f2=ID -> < f2=ID
+ '''
+ Assert.assertEquals(expected, actual)
+ }
+
+ @Test @Ignore def void testParameter1() {
+ val actual = '''
+ M: "kw1" s=S | "kw2" s=S;
+ S :
v1=ID | v2=ID;
+ '''.toPda
+ val expected = '''
+ Greeting:
+ start -> '(', val=ID
+ '(' -> >>Greeting
+ ')' -> {Foo.child=}
+ < ')'
+ >>Greeting -> '(', val=ID
+ val=ID -> < < pda, String name) {
+ val test = Thread.currentThread.stackTrace.get(6).methodName
+ new PdaToDot().draw(pda, "dot2/" + test + "_" + name + ".pdf", "-T pdf")
+
+ }
+
+ def private toListString(Pda pda) {
+ val ts = new GrammarElementTitleSwitch().showAssignments().hideCardinality().showQualified()
+ val formatter = new PdaListFormatter();
+ formatter.setStateFormatter [
+ switch (type) { case START: "start" case STOP: "stop" default: ts.apply(grammarElement) }
+ ];
+ formatter.setStackitemFormatter(new GrammarElementTitleSwitch().showAssignments().hideCardinality());
+ formatter.sortFollowers();
+ return formatter.format(pda) + "\n"
+ }
+}
\ No newline at end of file
diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/SequencerTestLanguage.xtext b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/SequencerTestLanguage.xtext
index 2b52f52bb..f471e47cc 100644
--- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/SequencerTestLanguage.xtext
+++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/SequencerTestLanguage.xtext
@@ -21,7 +21,8 @@ Model:
x19=DependentAlternative1 | x20=DependentAlternative2 | x21=Optional | x22=Float |
x23=UnorderedAlternative | x24=UnorderedGroup | x25=UnorderedGroupOptional |
x26=UnorderedGroupBoolean | x27=Complex1 | x28=OptionalDouble |
- x29=NullValueGenerated | x30=NullValueInterpreted | x31=NullCrossRefGenerated | x32=NullCrossRefInterpreted;
+ x29=NullValueGenerated | x30=NullValueInterpreted | x31=NullCrossRefGenerated | x32=NullCrossRefInterpreted |
+ x33=FragmentCaller;
SimpleGroup:
"#1" val1=ID val2=ID;
@@ -169,4 +170,10 @@ NullCrossRefGenerated returns NullCrossRef:
"#31" ref=[ecore::EObject|ID];
NullCrossRefInterpreted returns NullCrossRef:
- "#32" ref=[ecore::EObject|ID] foo=ID?;
\ No newline at end of file
+ "#32" ref=[ecore::EObject|ID] foo=ID?;
+
+FragmentCaller returns FragmentCallerType:
+ "#33" val1=ID Fragment1 val=ID;
+
+fragment Fragment1 returns FragmentCallerType:
+ fragVal=ID;
\ No newline at end of file
diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/SyntacticSequencerPDAProviderTest.java b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/SyntacticSequencerPDAProviderTest.java
index 9a3e90e7b..9b1ab2367 100644
--- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/SyntacticSequencerPDAProviderTest.java
+++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/serializer/SyntacticSequencerPDAProviderTest.java
@@ -23,7 +23,8 @@ import org.eclipse.xtext.grammaranalysis.IPDAState.PDAStateType;
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
import org.eclipse.xtext.junit4.AbstractXtextTests;
import org.eclipse.xtext.serializer.analysis.Context2NameFunction;
-import org.eclipse.xtext.serializer.analysis.IContextProvider;
+import org.eclipse.xtext.serializer.analysis.IContextPDAProvider;
+import org.eclipse.xtext.serializer.analysis.IContextTypePDAProvider;
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider;
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider.ISynAbsorberState;
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider.ISynState;
@@ -71,14 +72,15 @@ public class SyntacticSequencerPDAProviderTest extends AbstractXtextTests {
public void drawGrammar(String path, Grammar grammar) {
try {
- IContextProvider contexts = get(IContextProvider.class);
+ IContextPDAProvider contexts = get(IContextPDAProvider.class);
+ IContextTypePDAProvider types = get(IContextTypePDAProvider.class);
SyntacticSequencerPDA2ExtendedDot seq2dot = get(SyntacticSequencerPDA2ExtendedDot.class);
for (EObject ctx : contexts.getAllContexts(grammar))
- for (EClass type : contexts.getTypesForContext(ctx))
- seq2dot.draw(
- new Pair(ctx, type),
+ for (EClass type : types.getTypesForContext(grammar, ctx))
+ seq2dot.draw(new Pair(ctx, type),
path + "-" + new Context2NameFunction().toFunction(grammar).apply(ctx) + "_"
- + (type == null ? "null" : type.getName()) + "-PDA.pdf", "-T pdf");
+ + (type == null ? "null" : type.getName()) + "-PDA.pdf",
+ "-T pdf");
} catch (IOException e) {
e.printStackTrace();
}
@@ -86,10 +88,11 @@ public class SyntacticSequencerPDAProviderTest extends AbstractXtextTests {
private List> getContexts(Grammar grammar) {
final Context2NameFunction ctx2name = get(Context2NameFunction.class);
- final IContextProvider contextProvider = get(IContextProvider.class);
+ final IContextPDAProvider contextProvider = get(IContextPDAProvider.class);
+ final IContextTypePDAProvider typeProvider = get(IContextTypePDAProvider.class);
List> result = Lists.newArrayList();
for (EObject ctx : contextProvider.getAllContexts(grammar))
- for (EClass type : contextProvider.getTypesForContext(ctx))
+ for (EClass type : typeProvider.getTypesForContext(grammar, ctx))
result.add(Tuples.create(type, ctx, ctx2name.getContextName(grammar, ctx)));
Collections.sort(result, new Comparator>() {
@Override
@@ -697,7 +700,11 @@ public class SyntacticSequencerPDAProviderTest extends AbstractXtextTests {
expected.append(" start '}'* greetings2+=Greeting2\n");
expected.append(" start '}'+ stop\n");
expected.append("null_AllElements:\n");
- expected.append(" start stop");
+ expected.append(" start stop\n");
+ expected.append("null_Elements:\n");
+ expected.append(" start >>Model '}'+ <ID? {ActionOnly} "kw2"? ID?;
\ No newline at end of file
+ "#14" "kw1"? =>ID? {ActionOnly} "kw2"? ID?;
+
+FragmentCaller returns FragmentCallerType:
+ "#15" val1=ID Fragment1 val=ID;
+
+fragment Fragment1 returns FragmentCallerType:
+ fragVal=ID;
\ No newline at end of file