mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 00:38:56 +00:00
WIP: Fixed serialization when fragments are involved
This commit is contained in:
parent
fe8e7cd250
commit
17e921798d
4 changed files with 110 additions and 30 deletions
org.eclipse.xtext.util/src/org/eclipse/xtext/util/formallang
org.eclipse.xtext/src/org/eclipse/xtext/serializer/analysis
|
@ -393,7 +393,7 @@ public class NfaUtil {
|
|||
name = "start:" + name;
|
||||
else if (s == nfa.getStop())
|
||||
name = "stop:" + name;
|
||||
names.put(name, s);
|
||||
names.put(name + System.identityHashCode(s), s);
|
||||
}
|
||||
List<String> sorted = Lists.newArrayList(names.keySet());
|
||||
Collections.sort(sorted);
|
||||
|
|
|
@ -350,8 +350,7 @@ public class PdaUtil {
|
|||
}
|
||||
|
||||
protected <S, P, E, T1, T2, D extends Pda<S, P>> void create(Cfg<E, T1> cfg, D pda, S state, E ele, Iterable<E> followerElements,
|
||||
FollowerFunction<E> ff, Function<E, T2> tokens, PdaFactory<D, S, P, ? super T2> fact, Map<E, S> states, Map<E, S> stops,
|
||||
Multimap<E, E> callers) {
|
||||
FollowerFunction<E> ff, Function<E, T2> tokens, PdaFactory<D, S, P, ? super T2> fact, Set<S> allStates, Multimap<E, E> callers) {
|
||||
List<S> followerStates = Lists.newArrayList();
|
||||
for (E fol : followerElements) {
|
||||
E e;
|
||||
|
@ -360,28 +359,24 @@ public class PdaUtil {
|
|||
if (root == cfg.getRoot())
|
||||
followerStates.add(pda.getStop());
|
||||
for (E c : callers.get(root)) {
|
||||
S s = stops.get(c);
|
||||
if (s == null) {
|
||||
s = fact.createPop(pda, tokens.apply(c));
|
||||
stops.put(c, s);
|
||||
create(cfg, pda, s, c, ff.getFollowers(c), ff, tokens, fact, states, stops, callers);
|
||||
S s = fact.createPop(pda, tokens.apply(c));
|
||||
if (s != null) {
|
||||
if (allStates.add(s)) {
|
||||
create(cfg, pda, s, c, ff.getFollowers(c), ff, tokens, fact, allStates, callers);
|
||||
}
|
||||
followerStates.add(s);
|
||||
}
|
||||
followerStates.add(s);
|
||||
}
|
||||
} else if ((e = cfg.getCall(fol)) != null) {
|
||||
S s = states.get(fol);
|
||||
if (s == null) {
|
||||
s = fact.createPush(pda, tokens.apply(fol));
|
||||
states.put(fol, s);
|
||||
create(cfg, pda, s, e, ff.getStarts(e), ff, tokens, fact, states, stops, callers);
|
||||
S s = fact.createPush(pda, tokens.apply(fol));
|
||||
if (allStates.add(s)) {
|
||||
create(cfg, pda, s, e, ff.getStarts(e), ff, tokens, fact, allStates, callers);
|
||||
}
|
||||
followerStates.add(s);
|
||||
} else {
|
||||
S s = states.get(fol);
|
||||
if (s == null) {
|
||||
s = fact.createState(pda, tokens.apply(fol));
|
||||
states.put(fol, s);
|
||||
create(cfg, pda, s, fol, ff.getFollowers(fol), ff, tokens, fact, states, stops, callers);
|
||||
S s = fact.createState(pda, tokens.apply(fol));
|
||||
if (allStates.add(s)) {
|
||||
create(cfg, pda, s, fol, ff.getFollowers(fol), ff, tokens, fact, allStates, callers);
|
||||
}
|
||||
followerStates.add(s);
|
||||
}
|
||||
|
@ -392,10 +387,8 @@ public class PdaUtil {
|
|||
public <S, P, E, T1, T2, D extends Pda<S, P>> D create(Cfg<E, T1> cfg, FollowerFunction<E> ff, Function<E, T2> element2token,
|
||||
PdaFactory<D, S, P, ? super T2> fact) {
|
||||
D pda = fact.create(null, null);
|
||||
Map<E, S> states = Maps.newLinkedHashMap();
|
||||
Map<E, S> stops = Maps.newLinkedHashMap();
|
||||
Multimap<E, E> callers = new CfgUtil().getCallers(cfg);
|
||||
create(cfg, pda, pda.getStart(), cfg.getRoot(), ff.getStarts(cfg.getRoot()), ff, element2token, fact, states, stops, callers);
|
||||
create(cfg, pda, pda.getStart(), cfg.getRoot(), ff.getStarts(cfg.getRoot()), ff, element2token, fact, new HashSet<>(), callers);
|
||||
return pda;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.serializer.analysis;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -37,6 +39,7 @@ import org.eclipse.xtext.xtext.RuleFilter;
|
|||
import org.eclipse.xtext.xtext.RuleNames;
|
||||
import org.eclipse.xtext.xtext.RuleWithParameterValues;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
@ -84,10 +87,71 @@ public class GrammarPDAProvider implements IGrammarPDAProvider {
|
|||
|
||||
protected static class ToOriginal implements PdaFactory<SerializerPDA, ISerState, RuleCall, AbstractElement> {
|
||||
|
||||
private static class CompositeSerState implements ISerState {
|
||||
final ISerState delegate;
|
||||
final ISerState parent;
|
||||
public CompositeSerState(ISerState delegate, ISerState parent) {
|
||||
this.delegate = delegate;
|
||||
this.parent = parent;
|
||||
}
|
||||
@Override
|
||||
public List<? extends ISerState> getFollowers() {
|
||||
return delegate.getFollowers();
|
||||
}
|
||||
@Override
|
||||
public List<? extends ISerState> getPrecedents() {
|
||||
return delegate.getPrecedents();
|
||||
}
|
||||
@Override
|
||||
public AbstractElement getGrammarElement() {
|
||||
return delegate.getGrammarElement();
|
||||
}
|
||||
@Override
|
||||
public SerStateType getType() {
|
||||
return delegate.getType();
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((delegate == null) ? 0 : delegate.hashCode());
|
||||
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CompositeSerState other = (CompositeSerState) obj;
|
||||
if (delegate == null) {
|
||||
if (other.delegate != null)
|
||||
return false;
|
||||
} else if (!delegate.equals(other.delegate))
|
||||
return false;
|
||||
if (parent == null) {
|
||||
if (other.parent != null)
|
||||
return false;
|
||||
} else if (!parent.equals(other.parent))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString() + " with parent: " + parent;
|
||||
}
|
||||
}
|
||||
|
||||
private final SerializerPDAElementFactory delegate;
|
||||
private final Map<AbstractElement, ISerState> pops = Maps.newHashMap();
|
||||
private final Map<AbstractElement, ISerState> pushs = Maps.newHashMap();
|
||||
private final Map<AbstractElement, ISerState> states = Maps.newHashMap();
|
||||
|
||||
private final ArrayDeque<ISerState> stateStack = new ArrayDeque<>();
|
||||
private final ArrayDeque<AbstractElement> callStack = new ArrayDeque<>();
|
||||
|
||||
public ToOriginal(SerializerPDAElementFactory delegate) {
|
||||
super();
|
||||
|
@ -102,11 +166,20 @@ public class GrammarPDAProvider implements IGrammarPDAProvider {
|
|||
@Override
|
||||
public ISerState createPop(SerializerPDA pda, AbstractElement token) {
|
||||
AbstractElement original = original(token);
|
||||
if (GrammarUtil.isEObjectFragmentRuleCall(original)) {
|
||||
if (callStack.peek() != original) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
ISerState state = pops.get(original);
|
||||
if (state == null) {
|
||||
state = delegate.createPop(pda, original);
|
||||
pops.put(original, state);
|
||||
}
|
||||
if (callStack.peek() == original) {
|
||||
stateStack.pop();
|
||||
callStack.pop();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@ -118,6 +191,10 @@ public class GrammarPDAProvider implements IGrammarPDAProvider {
|
|||
state = delegate.createPush(pda, original);
|
||||
pushs.put(original, state);
|
||||
}
|
||||
if (GrammarUtil.isEObjectFragmentRuleCall(original)) {
|
||||
stateStack.push(state);
|
||||
callStack.push(original);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@ -125,8 +202,16 @@ public class GrammarPDAProvider implements IGrammarPDAProvider {
|
|||
public ISerState createState(SerializerPDA nfa, AbstractElement token) {
|
||||
AbstractElement original = original(token);
|
||||
ISerState state = states.get(original);
|
||||
if (state instanceof CompositeSerState && !stateStack.isEmpty()) {
|
||||
if (((CompositeSerState)state).parent != stateStack.peek()) {
|
||||
state = null;
|
||||
}
|
||||
}
|
||||
if (state == null) {
|
||||
state = delegate.createState(nfa, original);
|
||||
if (!stateStack.isEmpty()) {
|
||||
state = new CompositeSerState(state, stateStack.peek());
|
||||
}
|
||||
states.put(original, state);
|
||||
}
|
||||
return state;
|
||||
|
@ -146,9 +231,10 @@ public class GrammarPDAProvider implements IGrammarPDAProvider {
|
|||
@Override
|
||||
public void setFollowers(SerializerPDA nfa, ISerState owner, Iterable<ISerState> followers) {
|
||||
Set<ISerState> all = Sets.newLinkedHashSet(owner.getFollowers());
|
||||
Iterables.addAll(all, followers);
|
||||
FluentIterable.from(followers).copyInto(all);
|
||||
delegate.setFollowers(nfa, owner, all);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Logger LOG = Logger.getLogger(GrammarPDAProvider.class);
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.eclipse.xtext.util.formallang.PdaFactory;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
public class SerializerPDA implements Pda<ISerState, RuleCall> {
|
||||
|
@ -88,10 +89,12 @@ public class SerializerPDA implements Pda<ISerState, RuleCall> {
|
|||
|
||||
@Override
|
||||
public void setFollowers(SerializerPDA nfa, ISerState owner, Iterable<ISerState> followers) {
|
||||
((SerializerPDA.SerializerPDAState) owner).followers = Lists.newArrayList(followers);
|
||||
List<ISerState> prevFollowers = (List<ISerState>) owner.getFollowers();
|
||||
prevFollowers.clear();
|
||||
FluentIterable.from(followers).copyInto(prevFollowers);
|
||||
for (ISerState follower : followers) {
|
||||
Preconditions.checkNotNull(follower);
|
||||
((SerializerPDA.SerializerPDAState) follower).precedents.add(owner);
|
||||
((List<ISerState>)follower.getPrecedents()).add(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,19 +206,17 @@ public class SerializerPDA implements Pda<ISerState, RuleCall> {
|
|||
|
||||
@Override
|
||||
public Iterable<ISerState> getFollowers(ISerState state) {
|
||||
return ((SerializerPDA.SerializerPDAState) state).followers;
|
||||
return (Iterable<ISerState>) state.getFollowers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleCall getPop(ISerState state) {
|
||||
SerializerPDA.SerializerPDAState s = (SerializerPDA.SerializerPDAState) state;
|
||||
return s.type == SerStateType.POP ? (RuleCall) s.grammarElement : null;
|
||||
return state.getType() == SerStateType.POP ? (RuleCall) state.getGrammarElement() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleCall getPush(ISerState state) {
|
||||
SerializerPDA.SerializerPDAState s = (SerializerPDA.SerializerPDAState) state;
|
||||
return s.type == SerStateType.PUSH ? (RuleCall) s.grammarElement : null;
|
||||
return state.getType() == SerStateType.PUSH ? (RuleCall) state.getGrammarElement() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue