mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 00:38:56 +00:00
parsetree reconstructor refactoring (part 1)
This commit is contained in:
parent
dcf7c578c7
commit
8e85cf47ed
21 changed files with 483 additions and 443 deletions
|
@ -17,7 +17,9 @@ Export-Package: org.eclipse.xtext,
|
|||
org.eclipse.xtext.parser.antlr,
|
||||
org.eclipse.xtext.parser.impl,
|
||||
org.eclipse.xtext.parsetree,
|
||||
org.eclipse.xtext.parsetree.internal,
|
||||
org.eclipse.xtext.parsetree.reconstr,
|
||||
org.eclipse.xtext.parsetree.reconstr.callbacks,
|
||||
org.eclipse.xtext.parsetree.reconstr.impl,
|
||||
org.eclipse.xtext.parsetree.util,
|
||||
org.eclipse.xtext.resource,
|
||||
org.eclipse.xtext.services,
|
||||
|
|
|
@ -70,6 +70,9 @@ AbstractRule calledRule(RuleCall this) :
|
|||
String getReturnTypeName(AbstractRule p) :
|
||||
JAVA org.eclipse.xtext.GrammarUtil.getReturnTypeName(org.eclipse.xtext.AbstractRule);
|
||||
|
||||
Assignment containingAssignment(emf::EObject this) :
|
||||
JAVA org.eclipse.xtext.GrammarUtil.containingAssignment(org.eclipse.emf.ecore.EObject);
|
||||
|
||||
Boolean isAssigned(emf::EObject this) :
|
||||
JAVA org.eclipse.xtext.GrammarUtil.isAssigned(org.eclipse.emf.ecore.EObject);
|
||||
|
||||
|
|
|
@ -34,6 +34,13 @@ import org.eclipse.xtext.util.Strings;
|
|||
* @author svenefftinge
|
||||
*/
|
||||
public class GrammarUtil {
|
||||
|
||||
public static ParserRule getDefaultEntryRule(Grammar g) {
|
||||
if (g.isAbstract())
|
||||
return null;
|
||||
return GrammarUtil.allParserRules(g).get(0);
|
||||
}
|
||||
|
||||
public static String getLanguageId(Grammar g) {
|
||||
return Strings.concat(".", g.getIdElements());
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package org.eclipse.xtext.parser;
|
||||
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.service.ILanguageService;
|
||||
|
||||
|
@ -48,4 +49,6 @@ public interface IAstFactory extends ILanguageService {
|
|||
public void add(EObject _this, String feature, Object value) throws RecognitionException;
|
||||
public void add(EObject _this, String feature, Object value, String lexerRule) throws RecognitionException;
|
||||
|
||||
public EClass getEClass(String fullTypeName);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
package org.eclipse.xtext.parsetree;
|
||||
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.conversion.IValueConverterService;
|
||||
import org.eclipse.xtext.parser.GenericEcoreElementFactory;
|
||||
import org.eclipse.xtext.parser.IAstFactory;
|
||||
import org.eclipse.xtext.service.Inject;
|
||||
|
||||
public abstract class AbstractParseTreeConstructor implements IParseTreeConstructor {
|
||||
private GenericEcoreElementFactory astElementFactory;
|
||||
|
||||
@Inject
|
||||
protected IValueConverterService converterService;
|
||||
|
||||
protected IValueConverterService getValueConverterService() {
|
||||
return converterService;
|
||||
}
|
||||
|
||||
private Grammar grammar;
|
||||
|
||||
@Inject
|
||||
protected void setElementFactory(IAstFactory astElementFactory) {
|
||||
this.astElementFactory = (GenericEcoreElementFactory) astElementFactory;
|
||||
}
|
||||
|
||||
protected GenericEcoreElementFactory getFactory() {
|
||||
return astElementFactory;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setGrammarAccess(IGrammarAccess grammarAccess) {
|
||||
this.grammar = grammarAccess.getGrammar();
|
||||
}
|
||||
|
||||
protected Grammar getGrammar() {
|
||||
return grammar;
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil;
|
|||
*
|
||||
*/
|
||||
public class NodeUtil {
|
||||
|
||||
public static NodeAdapter getNodeAdapter(EObject obj) {
|
||||
return (NodeAdapter) EcoreUtil.getAdapter(obj.eAdapters(), AbstractNode.class);
|
||||
}
|
||||
|
@ -81,6 +82,17 @@ public class NodeUtil {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static EObject findASTParentElement(CompositeNode replaceRootNode) {
|
||||
CompositeNode parent = replaceRootNode.getParent();
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
if (parent.getElement() != null) {
|
||||
return parent.getElement();
|
||||
}
|
||||
return findASTParentElement(parent);
|
||||
}
|
||||
|
||||
public static void dumpCompositeNodes(String indent, CompositeNode node) {
|
||||
dumpCompositeNodeInfo(indent, node);
|
||||
|
|
|
@ -1,290 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.parsetree.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.emf.common.util.EList;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
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.Action;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.LexerRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.conversion.IValueConverterService;
|
||||
import org.eclipse.xtext.parser.GenericEcoreElementFactory;
|
||||
import org.eclipse.xtext.parsetree.AbstractNode;
|
||||
import org.eclipse.xtext.parsetree.CompositeNode;
|
||||
import org.eclipse.xtext.parsetree.LeafNode;
|
||||
import org.eclipse.xtext.parsetree.NodeAdapter;
|
||||
import org.eclipse.xtext.parsetree.NodeAdapterFactory;
|
||||
import org.eclipse.xtext.parsetree.ParsetreeFactory;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractInternalParseTreeConstructor {
|
||||
|
||||
|
||||
private GenericEcoreElementFactory factory;
|
||||
private Grammar grammar;
|
||||
private IValueConverterService converterService;
|
||||
|
||||
public AbstractInternalParseTreeConstructor(GenericEcoreElementFactory factory, Grammar grammar, IValueConverterService converterService) {
|
||||
this.factory =factory;
|
||||
this.grammar = grammar;
|
||||
this.converterService = converterService;
|
||||
}
|
||||
|
||||
protected Grammar getGrammar() {
|
||||
return grammar;
|
||||
}
|
||||
|
||||
protected GenericEcoreElementFactory getFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
public void update(EObject object) {
|
||||
NodeAdapter adapter = getAdapter(object);
|
||||
CompositeNode rootNode = null;
|
||||
String ruleToCall = GrammarUtil.allParserRules(getGrammar()).get(0).getName();
|
||||
if (adapter == null) {
|
||||
rootNode = ParsetreeFactory.eINSTANCE.createCompositeNode();
|
||||
object = EcoreUtil.getRootContainer(object);
|
||||
// TODO set synthetic rulecall
|
||||
} else {
|
||||
rootNode = adapter.getParserNode();
|
||||
rootNode.getChildren().clear();
|
||||
if (rootNode.getGrammarElement() instanceof RuleCall) {
|
||||
ruleToCall = ((RuleCall) rootNode.getGrammarElement()).getName();
|
||||
}
|
||||
object = rootNode.getElement();
|
||||
}
|
||||
internalDoUpdate(object, ruleToCall);
|
||||
}
|
||||
|
||||
protected abstract void internalDoUpdate(EObject obj, String ruleToCall);
|
||||
|
||||
private NodeAdapter getAdapter(EObject object) {
|
||||
NodeAdapter adapter = (NodeAdapter) EcoreUtil.getAdapter(object.eAdapters(), AbstractNode.class);
|
||||
if ((adapter == null || !(adapter.getParserNode().getGrammarElement() instanceof RuleCall))
|
||||
&& object.eContainer() != null) {
|
||||
return getAdapter(object.eContainer());
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
||||
protected final InstanceDescription getDescr(InstanceDescription obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected final InstanceDescription getDescr(EObject obj) {
|
||||
return new InstanceDescription(obj, false);
|
||||
}
|
||||
|
||||
protected final InstanceDescription getDescr(EObject obj, boolean lookahead) {
|
||||
return new InstanceDescription(obj, lookahead);
|
||||
}
|
||||
|
||||
public final class InstanceDescription {
|
||||
|
||||
public boolean isInstanceOf(String string) {
|
||||
EClass class1 = getFactory().getEClass(string);
|
||||
return class1 != null && class1.isSuperTypeOf(getDelegate().eClass());
|
||||
}
|
||||
|
||||
public boolean isOfType(String string) {
|
||||
EClass class1 = getFactory().getEClass(string);
|
||||
return class1 != null && class1.equals(getDelegate().eClass());
|
||||
}
|
||||
|
||||
public EObject getDelegate() {
|
||||
return described;
|
||||
}
|
||||
|
||||
private boolean isLookahead = false;
|
||||
|
||||
private EObject described;
|
||||
private Map<String, Integer> featureConsumedCounter = new HashMap<String, Integer>();
|
||||
|
||||
public InstanceDescription(EObject described, boolean lookahead) {
|
||||
super();
|
||||
if (described == null)
|
||||
throw new NullPointerException("described");
|
||||
this.described = described;
|
||||
this.isLookahead = lookahead;
|
||||
EList<EStructuralFeature> features = described.eClass().getEAllStructuralFeatures();
|
||||
for (EStructuralFeature f : features) {
|
||||
Integer integer = 0;
|
||||
if (described.eIsSet(f)) {
|
||||
if (f.isMany()) {
|
||||
integer = ((List<?>) described.eGet(f)).size();
|
||||
} else {
|
||||
integer = 1;
|
||||
}
|
||||
}
|
||||
featureConsumedCounter.put(f.getName(), integer);
|
||||
}
|
||||
}
|
||||
|
||||
private InstanceDescription(EObject described, Map<String, Integer> featureConsumedCounter) {
|
||||
super();
|
||||
this.isLookahead = true;
|
||||
this.described = described;
|
||||
this.featureConsumedCounter = featureConsumedCounter;
|
||||
}
|
||||
|
||||
public boolean isLookahead() {
|
||||
return isLookahead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return hashCode() + "/" + described.hashCode();
|
||||
}
|
||||
|
||||
public Object consume(String feature) {
|
||||
if (!isConsumable(feature))
|
||||
throw new IllegalStateException(feature + " is not consumable");
|
||||
Integer counter = lazyGet(feature);
|
||||
EStructuralFeature f = getFeature(feature);
|
||||
Object get = described.eGet(f);
|
||||
if (f.isMany()) {
|
||||
List<?> list = (List<?>) get;
|
||||
get = list.get(counter - 1);
|
||||
}
|
||||
featureConsumedCounter.put(feature, counter - 1);
|
||||
return get;
|
||||
}
|
||||
|
||||
public boolean checkConsume(String feature) {
|
||||
if (!isConsumable(feature))
|
||||
return false;
|
||||
Integer counter = lazyGet(feature);
|
||||
EStructuralFeature f = getFeature(feature);
|
||||
Object get = described.eGet(f);
|
||||
if (f.isMany()) {
|
||||
List<?> list = (List<?>) get;
|
||||
get = list.get(counter - 1);
|
||||
}
|
||||
featureConsumedCounter.put(feature, counter - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
private Integer lazyGet(String feature) {
|
||||
Integer integer = featureConsumedCounter.get(feature);
|
||||
if (integer == null) {
|
||||
return 0;
|
||||
}
|
||||
return integer;
|
||||
}
|
||||
|
||||
private EStructuralFeature getFeature(String feature) {
|
||||
return described.eClass().getEStructuralFeature(feature);
|
||||
}
|
||||
|
||||
public boolean isConsumable(String feature) {
|
||||
return lazyGet(feature) > 0;
|
||||
}
|
||||
|
||||
public boolean isConsumed() {
|
||||
for (Integer i : featureConsumedCounter.values()) {
|
||||
if (i > 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public InstanceDescription newLookaheadDescription() {
|
||||
return new InstanceDescription(described, new HashMap<String, Integer>(featureConsumedCounter));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private CompositeNode current = ParsetreeFactory.eINSTANCE.createCompositeNode();
|
||||
private LexerRule wsRule;
|
||||
|
||||
protected void ruleCallStart(InstanceDescription val, boolean isAssigned, RuleCall ruleCall) {
|
||||
CompositeNode node = ParsetreeFactory.eINSTANCE.createCompositeNode();
|
||||
node.setGrammarElement(ruleCall);
|
||||
prependToCurrentsChildren(node);
|
||||
current = node;
|
||||
}
|
||||
|
||||
protected void ruleCallEnd(InstanceDescription val, boolean b, RuleCall ruleCall) {
|
||||
current = current.getParent();
|
||||
}
|
||||
|
||||
private void prependToCurrentsChildren(AbstractNode node) {
|
||||
current.getChildren().add(0, node);
|
||||
}
|
||||
|
||||
protected void lexerRuleCall(RuleCall ruleCall) {
|
||||
throw new UnsupportedOperationException("coudn't generate text for lexer rule " + ruleCall.getName());
|
||||
}
|
||||
|
||||
protected void lexerRuleCall(Object value, RuleCall ruleCall) {
|
||||
checkWhitespace();
|
||||
LeafNode ln = ParsetreeFactory.eINSTANCE.createLeafNode();
|
||||
ln.setGrammarElement(ruleCall);
|
||||
ln.setText(converterService.toString(value, ruleCall.getName()));
|
||||
prependToCurrentsChildren(ln);
|
||||
}
|
||||
|
||||
private void checkWhitespace() {
|
||||
EList<LeafNode> leafNodes = ((CompositeNode) EcoreUtil.getRootContainer(current)).getLeafNodes();
|
||||
if (!leafNodes.isEmpty()) {
|
||||
LeafNode next = leafNodes.get(0);
|
||||
if (!next.isHidden()) {
|
||||
LeafNode ws = ParsetreeFactory.eINSTANCE.createLeafNode();
|
||||
ws.setText(" ");
|
||||
ws.setGrammarElement(getWhitespaceRule());
|
||||
prependToCurrentsChildren(ws);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LexerRule getWhitespaceRule() {
|
||||
if (wsRule == null) {
|
||||
// TODO
|
||||
}
|
||||
return wsRule;
|
||||
}
|
||||
|
||||
protected void action(InstanceDescription parent, InstanceDescription child, Action action) {
|
||||
objectCreation(parent);
|
||||
}
|
||||
|
||||
protected void keyword(Keyword kw) {
|
||||
checkWhitespace();
|
||||
LeafNode ln = ParsetreeFactory.eINSTANCE.createLeafNode();
|
||||
ln.setGrammarElement(kw);
|
||||
ln.setText(converterService.toString(kw.getValue(), kw.getValue()));
|
||||
prependToCurrentsChildren(ln);
|
||||
}
|
||||
|
||||
protected void objectCreation(InstanceDescription obj) {
|
||||
current.setElement(obj.getDelegate());
|
||||
NodeAdapter newOne = (NodeAdapter) NodeAdapterFactory.INSTANCE.adapt(obj.getDelegate(), AbstractNode.class);
|
||||
newOne.setParserNode(current);
|
||||
}
|
||||
|
||||
protected EObject getGrammarElement(String string) {
|
||||
return getGrammar().eResource().getResourceSet().getEObject(URI.createURI(string), true);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.eclipse.xtext.parsetree.reconstr;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
|
||||
public interface IInstanceDescription {
|
||||
|
||||
public abstract boolean isInstanceOf(String string);
|
||||
|
||||
public abstract boolean isOfType(String string);
|
||||
|
||||
public abstract EObject getDelegate();
|
||||
|
||||
public abstract Object get(String feature);
|
||||
|
||||
public abstract boolean isConsumable(String feature);
|
||||
|
||||
public abstract boolean isConsumed();
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.parsetree;
|
||||
package org.eclipse.xtext.parsetree.reconstr;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.service.ILanguageService;
|
||||
|
@ -16,5 +16,5 @@ import org.eclipse.xtext.service.ILanguageService;
|
|||
*
|
||||
*/
|
||||
public interface IParseTreeConstructor extends ILanguageService {
|
||||
public void update(EObject object);
|
||||
public void update(EObject object, IParseTreeConstructorCallback callback);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.eclipse.xtext.parsetree.reconstr;
|
||||
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
|
||||
public interface IParseTreeConstructorCallback {
|
||||
void parserRuleCallStart(IInstanceDescription current, RuleCall call);
|
||||
void parserRuleCallEnd();
|
||||
void objectCreation(IInstanceDescription current);
|
||||
void lexerRuleCall(IInstanceDescription current, RuleCall call);
|
||||
void keywordCall(IInstanceDescription current, Keyword call);
|
||||
void actionCall(IInstanceDescription oldCurrent,IInstanceDescription newCurrent, Action action);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.eclipse.xtext.parsetree.reconstr.callbacks;
|
||||
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IInstanceDescription;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IParseTreeConstructorCallback;
|
||||
|
||||
public class DefaultParsetreeReconstructorCallback implements IParseTreeConstructorCallback {
|
||||
|
||||
public void actionCall(IInstanceDescription oldCurrent, IInstanceDescription newCurrent, Action action) {
|
||||
}
|
||||
|
||||
public void keywordCall(IInstanceDescription current, Keyword call) {
|
||||
}
|
||||
|
||||
public void lexerRuleCall(IInstanceDescription current, RuleCall call) {
|
||||
}
|
||||
|
||||
public void objectCreation(IInstanceDescription current) {
|
||||
}
|
||||
|
||||
public void parserRuleCallEnd() {
|
||||
}
|
||||
|
||||
public void parserRuleCallStart(IInstanceDescription current, RuleCall call) {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.eclipse.xtext.parsetree.reconstr.callbacks;
|
||||
|
||||
import org.eclipse.xtext.Assignment;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.conversion.IValueConverterService;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IInstanceDescription;
|
||||
|
||||
public class SimpleSerializingCallback extends DefaultParsetreeReconstructorCallback {
|
||||
private StringBuffer buff = new StringBuffer();
|
||||
private IValueConverterService converterService;
|
||||
|
||||
public SimpleSerializingCallback(IValueConverterService converterService) {
|
||||
this.converterService = converterService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keywordCall(IInstanceDescription current, Keyword call) {
|
||||
if (buff.length()>0)
|
||||
prepend(" ");
|
||||
prepend(call.getValue());
|
||||
}
|
||||
|
||||
private void prepend(String s) {
|
||||
buff.insert(0, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lexerRuleCall(IInstanceDescription current, RuleCall call) {
|
||||
Assignment assignment = GrammarUtil.containingAssignment(call);
|
||||
Object value = null;
|
||||
if (assignment!=null) {
|
||||
value = current.get(assignment.getFeature());
|
||||
}
|
||||
if (buff.length()>0)
|
||||
prepend(" ");
|
||||
prepend(converterService.toString(value, call.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return buff.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package org.eclipse.xtext.parsetree.reconstr.impl;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.conversion.IValueConverterService;
|
||||
import org.eclipse.xtext.parser.IAstFactory;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IInstanceDescription;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IParseTreeConstructor;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IParseTreeConstructorCallback;
|
||||
import org.eclipse.xtext.service.Inject;
|
||||
|
||||
public abstract class AbstractParseTreeConstructor implements IParseTreeConstructor {
|
||||
@Inject
|
||||
private IAstFactory factory;
|
||||
|
||||
@Inject
|
||||
protected IValueConverterService converterService;
|
||||
|
||||
@Inject
|
||||
private IGrammarAccess grammar;
|
||||
|
||||
public IAstFactory getFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
protected Grammar getGrammar() {
|
||||
return grammar.getGrammar();
|
||||
}
|
||||
|
||||
protected IValueConverterService getValueConverterService() {
|
||||
return converterService;
|
||||
}
|
||||
|
||||
|
||||
public void update(EObject object, IParseTreeConstructorCallback callback) {
|
||||
EObject root = EcoreUtil.getRootContainer(object);
|
||||
ParserRule parserRule = GrammarUtil.getDefaultEntryRule(getGrammar());
|
||||
String ruleToCall = parserRule.getName();
|
||||
internalDoUpdate(root, ruleToCall,callback);
|
||||
}
|
||||
protected abstract void internalDoUpdate(EObject obj, String ruleToCall, IParseTreeConstructorCallback callback);
|
||||
|
||||
protected final InstanceDescription getDescr(EObject obj) {
|
||||
return new InstanceDescription(this, obj);
|
||||
}
|
||||
|
||||
protected final IInstanceDescription getDescr(IInstanceDescription obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected EObject getGrammarElement(String string) {
|
||||
return grammar.getGrammar().eResource().getResourceSet().getEObject(URI.createURI(string), true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.parsetree.reconstr.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.emf.common.util.EList;
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.EStructuralFeature;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IInstanceDescription;
|
||||
|
||||
public class InstanceDescription implements IInstanceDescription {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private AbstractParseTreeConstructor parseTreeConstr;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#isInstanceOf(java.lang.String)
|
||||
*/
|
||||
public boolean isInstanceOf(String string) {
|
||||
EClass class1 = this.parseTreeConstr.getFactory().getEClass(string);
|
||||
return class1 != null && class1.isSuperTypeOf(getDelegate().eClass());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#isOfType(java.lang.String)
|
||||
*/
|
||||
public boolean isOfType(String string) {
|
||||
EClass class1 = this.parseTreeConstr.getFactory().getEClass(string);
|
||||
return class1 != null && class1.equals(getDelegate().eClass());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#getDelegate()
|
||||
*/
|
||||
public EObject getDelegate() {
|
||||
return described;
|
||||
}
|
||||
|
||||
private EObject described;
|
||||
private Map<String, Integer> featureConsumedCounter = new HashMap<String, Integer>();
|
||||
|
||||
public InstanceDescription(AbstractParseTreeConstructor abstractInternalParseTreeConstructor, EObject described) {
|
||||
super();
|
||||
this.parseTreeConstr = abstractInternalParseTreeConstructor;
|
||||
if (described == null)
|
||||
throw new NullPointerException("described");
|
||||
this.described = described;
|
||||
EList<EStructuralFeature> features = described.eClass().getEAllStructuralFeatures();
|
||||
for (EStructuralFeature f : features) {
|
||||
Integer integer = 0;
|
||||
if (described.eIsSet(f)) {
|
||||
if (f.isMany()) {
|
||||
integer = ((List<?>) described.eGet(f)).size();
|
||||
} else {
|
||||
integer = 1;
|
||||
}
|
||||
}
|
||||
featureConsumedCounter.put(f.getName(), integer);
|
||||
}
|
||||
}
|
||||
|
||||
private InstanceDescription(AbstractParseTreeConstructor abstractInternalParseTreeConstructor, EObject described, Map<String, Integer> featureConsumedCounter) {
|
||||
super();
|
||||
this.parseTreeConstr = abstractInternalParseTreeConstructor;
|
||||
this.described = described;
|
||||
this.featureConsumedCounter = featureConsumedCounter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return hashCode() + "/" + described.hashCode();
|
||||
}
|
||||
|
||||
public Object consume(String feature) {
|
||||
if (!isConsumable(feature))
|
||||
throw new IllegalStateException(feature + " is not consumable");
|
||||
Integer counter = lazyGet(feature);
|
||||
EStructuralFeature f = getFeature(feature);
|
||||
Object get = described.eGet(f);
|
||||
if (f.isMany()) {
|
||||
List<?> list = (List<?>) get;
|
||||
get = list.get(counter - 1);
|
||||
}
|
||||
featureConsumedCounter.put(feature, counter - 1);
|
||||
return get;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#get(java.lang.String)
|
||||
*/
|
||||
public Object get(String feature) {
|
||||
Integer counter = lazyGet(feature);
|
||||
EStructuralFeature f = getFeature(feature);
|
||||
Object get = described.eGet(f);
|
||||
if (f.isMany()) {
|
||||
List<?> list = (List<?>) get;
|
||||
get = list.get(counter);
|
||||
}
|
||||
return get;
|
||||
}
|
||||
|
||||
public boolean checkConsume(String feature) {
|
||||
if (!isConsumable(feature))
|
||||
return false;
|
||||
Integer counter = lazyGet(feature);
|
||||
EStructuralFeature f = getFeature(feature);
|
||||
Object get = described.eGet(f);
|
||||
if (f.isMany()) {
|
||||
List<?> list = (List<?>) get;
|
||||
get = list.get(counter - 1);
|
||||
}
|
||||
featureConsumedCounter.put(feature, counter - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
private Integer lazyGet(String feature) {
|
||||
Integer integer = featureConsumedCounter.get(feature);
|
||||
if (integer == null) {
|
||||
return 0;
|
||||
}
|
||||
return integer;
|
||||
}
|
||||
|
||||
private EStructuralFeature getFeature(String feature) {
|
||||
return described.eClass().getEStructuralFeature(feature);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#isConsumable(java.lang.String)
|
||||
*/
|
||||
public boolean isConsumable(String feature) {
|
||||
return lazyGet(feature) > 0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#isConsumed()
|
||||
*/
|
||||
public boolean isConsumed() {
|
||||
for (Integer i : featureConsumedCounter.values()) {
|
||||
if (i > 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public InstanceDescription clone() {
|
||||
return new InstanceDescription(this.parseTreeConstr, described, new HashMap<String, Integer>(featureConsumedCounter));
|
||||
}
|
||||
|
||||
}
|
|
@ -6,9 +6,8 @@
|
|||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.parsetree;
|
||||
package org.eclipse.xtext.parsetree.reconstr.impl;
|
||||
|
||||
import org.eclipse.xtext.parsetree.internal.AbstractInternalParseTreeConstructor.InstanceDescription;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -20,7 +19,7 @@ public abstract class Predicate {
|
|||
protected InstanceDescription obj;
|
||||
|
||||
public Predicate(InstanceDescription obj) {
|
||||
this.obj = obj.newLookaheadDescription();
|
||||
this.obj = obj.clone();
|
||||
}
|
||||
|
||||
public abstract boolean check();
|
|
@ -23,7 +23,6 @@ import org.eclipse.xtext.parser.IParseResult;
|
|||
import org.eclipse.xtext.parser.IParser;
|
||||
import org.eclipse.xtext.parsetree.AbstractNode;
|
||||
import org.eclipse.xtext.parsetree.CompositeNode;
|
||||
import org.eclipse.xtext.parsetree.IParseTreeConstructor;
|
||||
import org.eclipse.xtext.parsetree.NodeAdapter;
|
||||
import org.eclipse.xtext.parsetree.NodeContentAdapter;
|
||||
import org.eclipse.xtext.service.Inject;
|
||||
|
@ -40,9 +39,6 @@ public class XtextResource extends ResourceImpl {
|
|||
@Inject
|
||||
private IAstFactory elementFactory;
|
||||
|
||||
@Inject
|
||||
private IParseTreeConstructor parsetreeConstructor;
|
||||
|
||||
private IParseResult parseResult;
|
||||
|
||||
public XtextResource(URI uri) {
|
||||
|
@ -95,7 +91,6 @@ public class XtextResource extends ResourceImpl {
|
|||
}
|
||||
if (!contents.isEmpty()) {
|
||||
EObject rootElement = contents.get(0);
|
||||
parsetreeConstructor.update(rootElement);
|
||||
NodeAdapter rootNodeAdapter = getNodeAdapter(rootElement);
|
||||
if (rootNodeAdapter != null) {
|
||||
CompositeNode rootNode = rootNodeAdapter.getParserNode();
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
package org.eclipse.xtext;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.parsetree.NodeUtil;
|
||||
import org.eclipse.xtext.parsetree.XtextGrammarTestParseTreeConstructor;
|
||||
import org.eclipse.xtext.tests.AbstractGeneratorTest;
|
||||
|
||||
/**
|
||||
|
@ -32,12 +30,4 @@ public class XtextGrammarTest extends AbstractGeneratorTest {
|
|||
assertWithXtend("'name'","parserRules.first().alternatives.feature",grammar);
|
||||
}
|
||||
|
||||
public void testSerialization() throws Exception {
|
||||
String model = "generate foo 'bar' Foo : ( 'stuff' '{' '}' STRING ) ? ;";
|
||||
EObject grammar = (EObject) getModel(model);
|
||||
XtextGrammarTestParseTreeConstructor ptc = (XtextGrammarTestParseTreeConstructor) getParseTreeConstructor();
|
||||
ptc.update(grammar);
|
||||
assertEquals(model, NodeUtil.getNodeAdapter(grammar).getParserNode().serialize());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
package org.eclipse.xtext.parsetree.reconstr;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.parsetree.IParseTreeConstructor;
|
||||
import org.eclipse.xtext.parsetree.NodeUtil;
|
||||
import org.eclipse.xtext.parsetree.reconstr.callbacks.SimpleSerializingCallback;
|
||||
import org.eclipse.xtext.tests.AbstractGeneratorTest;
|
||||
import org.eclipse.xtext.xtext2ecore.EcoreModelComparator;
|
||||
|
||||
public class ComplexReconstrTest extends AbstractGeneratorTest {
|
||||
|
||||
|
@ -34,16 +34,21 @@ public class ComplexReconstrTest extends AbstractGeneratorTest {
|
|||
private String parseAndSerialize(String model) throws Exception {
|
||||
EObject result = (EObject) getModel(model);
|
||||
IParseTreeConstructor con = getParseTreeConstructor();
|
||||
con.update(result);
|
||||
String resultString = NodeUtil.getRootNode(result).serialize();
|
||||
return resultString;
|
||||
SimpleSerializingCallback callback = new SimpleSerializingCallback(getValueConverterService());
|
||||
con.update(result,callback);
|
||||
return callback.toString();
|
||||
}
|
||||
|
||||
public void testNormalizableCompositeNodesIncluded() throws Exception {
|
||||
reconstructAndCompare("a");
|
||||
reconstructAndCompare("a + b");
|
||||
}
|
||||
|
||||
private void reconstructAndCompare(String mymodel) throws Exception, InterruptedException {
|
||||
EObject model = getModel(mymodel);
|
||||
EObject model2 = getModel(parseAndSerialize(mymodel));
|
||||
EcoreModelComparator ecoreModelComparator = new EcoreModelComparator();
|
||||
assertFalse(ecoreModelComparator.modelsDiffer(model, model2));
|
||||
}
|
||||
|
||||
// public void testNormalizableCompositeNodesIncluded() throws Exception {
|
||||
// EObject model = getModel("a");
|
||||
// IParseTreeConstructor con = getParseTreeConstructor();
|
||||
// con.update(model);
|
||||
// CompositeNode node = NodeUtil.getRootNode(model);
|
||||
// assertEquals("Op",((RuleCall)node.getGrammarElement()).getName());
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
package org.eclipse.xtext.parsetree.reconstr;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.parsetree.IParseTreeConstructor;
|
||||
import org.eclipse.xtext.parsetree.NodeUtil;
|
||||
import org.eclipse.xtext.parsetree.reconstr.callbacks.SimpleSerializingCallback;
|
||||
import org.eclipse.xtext.testlanguages.SimpleExpressionsStandaloneSetup;
|
||||
import org.eclipse.xtext.tests.AbstractGeneratorTest;
|
||||
|
||||
|
@ -31,19 +30,15 @@ public class SimpleReconstrTest extends AbstractGeneratorTest {
|
|||
private String parseAndSerialize(String model) throws Exception {
|
||||
EObject result = (EObject) getModel(model);
|
||||
IParseTreeConstructor con = getParseTreeConstructor();
|
||||
con.update(result);
|
||||
String resultString = NodeUtil.getRootNode(result).serialize();
|
||||
return resultString;
|
||||
SimpleSerializingCallback callback = new SimpleSerializingCallback(getValueConverterService());
|
||||
con.update(result, callback);
|
||||
return callback.toString();
|
||||
}
|
||||
|
||||
public void testSimpleExpressions() throws Exception {
|
||||
with(SimpleExpressionsStandaloneSetup.class);
|
||||
String model = "a + b - c * d / e";
|
||||
EObject result = (EObject) getModel(model);
|
||||
IParseTreeConstructor con = getParseTreeConstructor();
|
||||
con.update(result);
|
||||
String resultString = NodeUtil.getRootNode(result).serialize();
|
||||
assertEquals(model,resultString);
|
||||
assertEquals(model,parseAndSerialize(model));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,10 +22,11 @@ import org.eclipse.emf.ecore.resource.ResourceSet;
|
|||
import org.eclipse.m2t.type.emf.EmfRegistryMetaModel;
|
||||
import org.eclipse.xtext.GenerateAllTestGrammars;
|
||||
import org.eclipse.xtext.XtextStandaloneSetup;
|
||||
import org.eclipse.xtext.conversion.IValueConverterService;
|
||||
import org.eclipse.xtext.parser.IAstFactory;
|
||||
import org.eclipse.xtext.parser.IParser;
|
||||
import org.eclipse.xtext.parsetree.CompositeNode;
|
||||
import org.eclipse.xtext.parsetree.IParseTreeConstructor;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IParseTreeConstructor;
|
||||
import org.eclipse.xtext.resource.IResourceFactory;
|
||||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
|
@ -89,17 +90,21 @@ public abstract class AbstractGeneratorTest extends TestCase {
|
|||
return ServiceRegistry.getService(currentLanguageDescriptor, IParser.class);
|
||||
}
|
||||
|
||||
protected IAstFactory getASTFactory() throws Exception {
|
||||
protected IAstFactory getASTFactory() {
|
||||
return ServiceRegistry.getService(currentLanguageDescriptor, IAstFactory.class);
|
||||
}
|
||||
|
||||
protected IParseTreeConstructor getParseTreeConstructor() throws Exception {
|
||||
protected IParseTreeConstructor getParseTreeConstructor() {
|
||||
return ServiceRegistry.getService(currentLanguageDescriptor, IParseTreeConstructor.class);
|
||||
}
|
||||
|
||||
protected IResourceFactory getResourceFactory() throws Exception {
|
||||
protected IResourceFactory getResourceFactory() {
|
||||
return ServiceRegistry.getService(currentLanguageDescriptor, IResourceFactory.class);
|
||||
}
|
||||
|
||||
protected IValueConverterService getValueConverterService() {
|
||||
return ServiceRegistry.getService(currentLanguageDescriptor, IValueConverterService.class);
|
||||
}
|
||||
|
||||
// parse methods
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ import org.eclipse.emf.ecore.EObject;
|
|||
import org.eclipse.emf.ecore.EReference;
|
||||
import org.eclipse.emf.ecore.EStructuralFeature;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
|
||||
/**
|
||||
* @author Jan Köhnlein
|
||||
|
@ -37,78 +39,101 @@ import org.eclipse.emf.ecore.resource.Resource;
|
|||
*/
|
||||
public class EcoreModelComparator {
|
||||
|
||||
private Map<String, Object> options;
|
||||
private IMatchEngine matchEngine;
|
||||
private List<EStructuralFeature> ignoredFeatures = new ArrayList<EStructuralFeature>();
|
||||
private Map<String, Object> options;
|
||||
private IMatchEngine matchEngine;
|
||||
private List<EStructuralFeature> ignoredFeatures = new ArrayList<EStructuralFeature>();
|
||||
|
||||
public EcoreModelComparator() {
|
||||
options = new HashMap<String, Object>();
|
||||
options.put(MatchOptions.OPTION_DISTINCT_METAMODELS, Boolean.TRUE);
|
||||
matchEngine = new GenericMatchEngine();
|
||||
}
|
||||
public EcoreModelComparator() {
|
||||
options = new HashMap<String, Object>();
|
||||
options.put(MatchOptions.OPTION_DISTINCT_METAMODELS, Boolean.TRUE);
|
||||
matchEngine = new GenericMatchEngine();
|
||||
}
|
||||
|
||||
public boolean modelsDiffer(Resource left, Resource right) throws InterruptedException {
|
||||
MatchModel matchModel = matchEngine.resourceMatch(left, right, options);
|
||||
return modelsDiffer(matchModel);
|
||||
}
|
||||
public boolean modelsDiffer(Resource left, Resource right) throws InterruptedException {
|
||||
MatchModel matchModel = matchEngine.resourceMatch(left, right, options);
|
||||
return modelsDiffer(matchModel);
|
||||
}
|
||||
|
||||
public boolean modelsDiffer(EObject left, EObject right) throws InterruptedException {
|
||||
MatchModel matchModel = matchEngine.modelMatch(left, right, options);
|
||||
return modelsDiffer(matchModel);
|
||||
}
|
||||
public boolean modelsDiffer(EObject left, EObject right) throws InterruptedException {
|
||||
try {
|
||||
addSyntheticResource(left);
|
||||
addSyntheticResource(right);
|
||||
MatchModel matchModel = matchEngine.modelMatch(left, right, options);
|
||||
return modelsDiffer(matchModel);
|
||||
} finally {
|
||||
removeSyntheticResource(left);
|
||||
removeSyntheticResource(right);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean modelsDiffer(MatchModel matchModel) {
|
||||
boolean modelsDiffer = false;
|
||||
DiffModel diffModel = DiffService.doDiff(matchModel);
|
||||
if (diffModel != null) {
|
||||
for (DiffElement diffElement : diffModel.getOwnedElements()) {
|
||||
modelsDiffer |= checkDiff(diffElement);
|
||||
}
|
||||
}
|
||||
return modelsDiffer;
|
||||
}
|
||||
private class SyntheticResource extends ResourceImpl {
|
||||
|
||||
}
|
||||
|
||||
public void addIgnoredFeature(EStructuralFeature feature) {
|
||||
ignoredFeatures.add(feature);
|
||||
}
|
||||
private void removeSyntheticResource(EObject o) {
|
||||
if (o.eResource() instanceof SyntheticResource) {
|
||||
o.eResource().getContents().clear();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkDiff(DiffElement diffElement) {
|
||||
boolean hasDiff = false;
|
||||
if (!ignoreDiff(diffElement)) {
|
||||
printDiff(diffElement);
|
||||
hasDiff = true;
|
||||
}
|
||||
for (DiffElement childDiffElement : diffElement.getSubDiffElements()) {
|
||||
hasDiff |= checkDiff(childDiffElement);
|
||||
}
|
||||
return hasDiff;
|
||||
}
|
||||
private void addSyntheticResource(EObject o) {
|
||||
if (o.eResource() == null) {
|
||||
new SyntheticResource().getContents().add(EcoreUtil.getRootContainer(o));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ignoreDiff(DiffElement diffElement) {
|
||||
if (diffElement instanceof AttributeChange) {
|
||||
return ignoredFeatures.contains(((AttributeChange) diffElement).getAttribute());
|
||||
} else if (diffElement instanceof ReferenceChange) {
|
||||
return ignoredFeatures.contains(((ReferenceChange) diffElement).getReference());
|
||||
}
|
||||
return diffElement instanceof DiffGroup;
|
||||
}
|
||||
private boolean modelsDiffer(MatchModel matchModel) {
|
||||
boolean modelsDiffer = false;
|
||||
DiffModel diffModel = DiffService.doDiff(matchModel);
|
||||
if (diffModel != null) {
|
||||
for (DiffElement diffElement : diffModel.getOwnedElements()) {
|
||||
modelsDiffer |= checkDiff(diffElement);
|
||||
}
|
||||
}
|
||||
return modelsDiffer;
|
||||
}
|
||||
|
||||
private void printDiff(DiffElement diffElement) {
|
||||
if (diffElement instanceof AttributeChange) {
|
||||
AttributeChange change = (AttributeChange) diffElement;
|
||||
EAttribute attribute = change.getAttribute();
|
||||
System.err.println("Detected attribute difference: " + attribute.getName());
|
||||
System.err.println("\t" + change.getLeftElement());
|
||||
System.err.println("\t" + change.getRightElement());
|
||||
} else if (diffElement instanceof ReferenceChange) {
|
||||
ReferenceChange change = (ReferenceChange) diffElement;
|
||||
EReference reference = change.getReference();
|
||||
System.err.println("Detected reference difference: " + reference.getName());
|
||||
System.err.println("\t" + change.getLeftElement());
|
||||
System.err.println("\t" + change.getRightElement());
|
||||
} else {
|
||||
// TODO: add more sysouts here...
|
||||
System.err.println(diffElement.toString());
|
||||
}
|
||||
}
|
||||
public void addIgnoredFeature(EStructuralFeature feature) {
|
||||
ignoredFeatures.add(feature);
|
||||
}
|
||||
|
||||
private boolean checkDiff(DiffElement diffElement) {
|
||||
boolean hasDiff = false;
|
||||
if (!ignoreDiff(diffElement)) {
|
||||
printDiff(diffElement);
|
||||
hasDiff = true;
|
||||
}
|
||||
for (DiffElement childDiffElement : diffElement.getSubDiffElements()) {
|
||||
hasDiff |= checkDiff(childDiffElement);
|
||||
}
|
||||
return hasDiff;
|
||||
}
|
||||
|
||||
private boolean ignoreDiff(DiffElement diffElement) {
|
||||
if (diffElement instanceof AttributeChange) {
|
||||
return ignoredFeatures.contains(((AttributeChange) diffElement).getAttribute());
|
||||
} else if (diffElement instanceof ReferenceChange) {
|
||||
return ignoredFeatures.contains(((ReferenceChange) diffElement).getReference());
|
||||
}
|
||||
return diffElement instanceof DiffGroup;
|
||||
}
|
||||
|
||||
private void printDiff(DiffElement diffElement) {
|
||||
if (diffElement instanceof AttributeChange) {
|
||||
AttributeChange change = (AttributeChange) diffElement;
|
||||
EAttribute attribute = change.getAttribute();
|
||||
System.err.println("Detected attribute difference: " + attribute.getName());
|
||||
System.err.println("\t" + change.getLeftElement());
|
||||
System.err.println("\t" + change.getRightElement());
|
||||
} else if (diffElement instanceof ReferenceChange) {
|
||||
ReferenceChange change = (ReferenceChange) diffElement;
|
||||
EReference reference = change.getReference();
|
||||
System.err.println("Detected reference difference: " + reference.getName());
|
||||
System.err.println("\t" + change.getLeftElement() +" "+reference.getName()+" = "+change.getLeftElement().eGet(reference));
|
||||
System.err.println("\t" + change.getRightElement()+" "+reference.getName()+" = "+change.getRightElement().eGet(reference));
|
||||
} else {
|
||||
// TODO: add more sysouts here...
|
||||
System.err.println(diffElement.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue