parsetree reconstructor refactoring (part 1)

This commit is contained in:
sefftinge 2008-07-04 13:49:07 +00:00
parent dcf7c578c7
commit 8e85cf47ed
21 changed files with 483 additions and 443 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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) {
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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());
// }
}

View file

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

View file

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

View file

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