WIP: Fixed serialization when fragments are involved

This commit is contained in:
Sebastian Zarnekow 2020-12-09 19:13:05 +01:00
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

View file

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

View file

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

View file

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

View file

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