org.eclipse.xtext.serializer.analysis.SemanticSequencerNfaProvider Maven / Gradle / Ivy
/*******************************************************************************
* 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.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.IGrammarAccess;
import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider.ISynAbsorberState;
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider.SynAbsorberNfaAdapter;
import org.eclipse.xtext.serializer.impl.FeatureFinderUtil;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.Tuples;
import org.eclipse.xtext.util.formallang.Nfa;
import org.eclipse.xtext.util.formallang.NfaFactory;
import org.eclipse.xtext.util.formallang.NfaUtil;
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;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
@Singleton
public class SemanticSequencerNfaProvider implements ISemanticSequencerNfaProvider {
protected static class SemNfa implements Nfa {
protected final ISemState start;
protected final ISemState stop;
public SemNfa(ISemState starts, ISemState stops) {
super();
this.start = starts;
this.stop = stops;
}
public List getFollowers(ISemState node) {
return node.getFollowers();
}
public ISemState getStart() {
return start;
}
public ISemState getStop() {
return stop;
}
}
protected static class SemState implements ISemState {
protected BitSet allFollowerFeatures;
protected AbstractElement assignedGrammarElement;
protected List contentValidationNeeded;
protected EStructuralFeature feature;
protected int featureID = -2;
protected List followers;
protected int orderID = 0;
protected EClass type;
public SemState(EClass type, AbstractElement assignedGrammarElement) {
super();
this.type = type;
this.assignedGrammarElement = assignedGrammarElement;
}
public BitSet getAllFollowerFeatures() {
if (allFollowerFeatures == null)
allFollowerFeatures = new BitSet();
return allFollowerFeatures;
}
public AbstractElement getAssignedGrammarElement() {
return assignedGrammarElement;
}
public EStructuralFeature getFeature() {
if (feature == null && assignedGrammarElement != null)
feature = FeatureFinderUtil.getFeature(assignedGrammarElement, type);
return feature;
}
public int getFeatureID() {
if (featureID < -1)
featureID = getFeature() != null ? type.getFeatureID(getFeature()) : -1;
return featureID;
}
public List getFollowers() {
return followers == null ? Collections. emptyList() : followers;
}
public int getOrderID() {
return orderID;
}
public List getToBeValidatedAssignedElements() {
return contentValidationNeeded;
}
@Override
public String toString() {
if (assignedGrammarElement == null)
return "(null)";
return new GrammarElementTitleSwitch().showQualified().showAssignments().apply(assignedGrammarElement);
}
}
protected static class SemStateFactory implements NfaFactory {
public SemNfa create(ISynAbsorberState start, ISynAbsorberState stop) {
SemState starts = new SemState(stop.getEClass(), stop.getGrammarElement());
SemState stops = new SemState(start.getEClass(), start.getGrammarElement());
return new SemNfa(starts, stops);
}
public ISemState createState(SemNfa nfa, ISynAbsorberState token) {
return new SemState(token.getEClass(), token.getGrammarElement());
}
public void setFollowers(SemNfa nfa, ISemState owner, Iterable followers) {
((SemState) owner).followers = Lists.newArrayList(followers);
}
}
protected Map elementIDCache;
@Inject
protected IGrammarAccess grammar;
@Inject
protected ISyntacticSequencerPDAProvider pdaProvider;
protected Map, Nfa> resultCache = Maps.newHashMap();
protected boolean addAll(BitSet to, BitSet bits) {
BitSet cpy = new BitSet();
cpy.or(to);
cpy.or(bits);
if (cpy.equals(to))
return false;
to.or(bits);
return true;
}
protected int getElementID(AbstractElement ele) {
if (elementIDCache == null) {
elementIDCache = Maps.newHashMap();
int counter = 0;
for (ParserRule pr : GrammarUtil.allParserRules(grammar.getGrammar()))
for (AbstractElement e : EcoreUtil2.getAllContentsOfType(pr, AbstractElement.class))
elementIDCache.put(e, counter++);
}
return elementIDCache.get(ele);
}
public Nfa getNFA(EObject context, EClass type) {
Pair key = Tuples.create(context, type);
Nfa nfa = resultCache.get(key);
if (nfa != null)
return nfa;
NfaUtil util = new NfaUtil();
SynAbsorberNfaAdapter synNfa = new SynAbsorberNfaAdapter(pdaProvider.getPDA(context, type));
// System.out.println(new NfaFormatter().format(synNfa));
Map distanceMap = util.distanceToFinalStateMap(synNfa);
nfa = util.create(util.sort(synNfa, distanceMap), new SemStateFactory());
// util.sortInplace(nfa, distanceMap);
if (type != null)
initContentValidationNeeded(type, nfa);
initRemainingFeatures(nfa.getStop(), util.inverse(nfa), Sets. newHashSet());
initOrderIDs(nfa);
// System.out.println(new NfaFormatter().format(nfa));
resultCache.put(key, nfa);
return nfa;
}
protected void initContentValidationNeeded(EClass clazz, Nfa nfa) {
Multimap assignments = HashMultimap.create();
Set states = new NfaUtil().collect(nfa);
for (ISemState state : states)
if (state.getFeature() != null)
assignments.put(state.getFeature(), state.getAssignedGrammarElement());
boolean[] validationNeeded = new boolean[clazz.getFeatureCount()];
for (EStructuralFeature feature : clazz.getEAllStructuralFeatures())
validationNeeded[clazz.getFeatureID(feature)] = isContentValidationNeeded(assignments.get(feature));
for (ISemState state : states)
if (state.getFeature() != null && validationNeeded[state.getFeatureID()])
((SemState) state).contentValidationNeeded = Lists.newArrayList(assignments.get(state.getFeature()));
else
((SemState) state).contentValidationNeeded = Collections.emptyList();
}
protected void initOrderIDs(Nfa nfa) {
for (ISemState state : new NfaUtil().collect(nfa))
if (state.getAssignedGrammarElement() != null)
((SemState) state).orderID = getElementID(state.getAssignedGrammarElement());
}
protected void initRemainingFeatures(ISemState state, Nfa inverseNfa, Set visited) {
BitSet features = state.getAllFollowerFeatures();
if (state.getFeature() != null) {
BitSet f = new BitSet();
f.or(features);
f.set(state.getFeatureID());
features = f;
}
for (ISemState follower : inverseNfa.getFollowers(state)) {
if (!addAll(follower.getAllFollowerFeatures(), features) && !visited.add(follower))
continue;
initRemainingFeatures(follower, inverseNfa, visited);
}
}
protected boolean isContentValidationNeeded(Collection ass) {
if (ass == null || ass.size() < 2)
return false;
Iterator it = ass.iterator();
AbstractElement first = it.next();
CrossReference firstRef = GrammarUtil.containingCrossReference(first);
while (it.hasNext()) {
AbstractElement next = it.next();
if (next instanceof Action)
return true;
if (!EcoreUtil.equals(first, next))
return true;
if (firstRef != null) {
CrossReference nextRef = GrammarUtil.containingCrossReference(next);
if (nextRef != null && nextRef.getType().getClassifier() != firstRef.getType().getClassifier())
return true;
}
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy