This commit is contained in:
sefftinge 2008-10-13 09:42:56 +00:00
parent bc8ef04c02
commit 13946fcd93
10 changed files with 214 additions and 72 deletions

View file

@ -114,6 +114,10 @@ public class GrammarUtil {
public static List<Keyword> containedKeywords(EObject e) {
return getAllContentsOfType(e, Keyword.class);
}
public static List<CrossReference> containedCrossReferences(EObject e) {
return getAllContentsOfType(e, CrossReference.class);
}
public static List<AbstractElement> elementsBeforeThisInContainingGroup(AbstractElement _this) {
Group g = containingGroup(_this);

View file

@ -38,6 +38,8 @@ context GeneratedMetamodel ERROR "Duplicate aliases are only allowed for referen
context AbstractRule ERROR "Name must be unique" :
grammar().rules.select(p | p.name == name).size==1;
// TODO: check that CrossReferences can only appear inside Assignments
/*
context ParserRule ERROR "Returned class " + getReturnTypeName() + " cannot be resolved" :

View file

@ -24,7 +24,7 @@ public interface IInstanceDescription {
* language
* @return true if the delegate's type is assignable to the given type
*/
public abstract boolean isOfType(String string);
// public abstract boolean isOfType(String string);
/**
* @return the wrapped EObject
@ -37,8 +37,15 @@ public interface IInstanceDescription {
* @param feature
* @return the consumed value
*/
public abstract Object get(String feature);
// public abstract Object get(String feature);
public Object getConsumable(String feature, boolean allowDefault);
public IInstanceDescription cloneAndConsume(String feature);
public boolean isConsumedWithLastConsumtion(String feature);
@Deprecated
public Object consume(String feature);
/**
@ -46,18 +53,22 @@ public interface IInstanceDescription {
* @param feature
* @return whether there are any consumable values for the given feature
*/
@Deprecated
public abstract boolean isConsumable(String feature);
/**
*
* @return whether all values referenced by the delegate have been consumed
*/
@Deprecated
public abstract boolean isConsumed();
/**
* @param feature
* @return the number of values already consumed for this feature
*/
public abstract int getConsumed(String feature);
// public abstract int getConsumed(String feature);
public IInstanceDescription createClone();
}

View file

@ -10,6 +10,7 @@ package org.eclipse.xtext.parsetree.reconstr;
import java.io.OutputStream;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.Keyword;
@ -34,8 +35,11 @@ public interface IParseTreeConstructorCallback extends ILanguageService {
void actionCall(IInstanceDescription oldCurrent,
IInstanceDescription newCurrent, Action action);
@Deprecated
void crossRefCall(IInstanceDescription current, CrossReference call);
void crossRefCall(IInstanceDescription current, CrossReference call, EObject value);
void beginSerialize(OutputStream output);

View file

@ -10,6 +10,7 @@ package org.eclipse.xtext.parsetree.reconstr.callbacks;
import java.io.OutputStream;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.Keyword;
@ -48,4 +49,7 @@ public class DefaultParsetreeReconstructorCallback implements IParseTreeConstruc
public void endSerialize() {
}
public void crossRefCall(IInstanceDescription current, CrossReference call, EObject value) {
}
}

View file

@ -6,9 +6,7 @@ import java.io.OutputStream;
import org.apache.log4j.Logger;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.conversion.IValueConverterService;
@ -18,7 +16,8 @@ import org.eclipse.xtext.service.Inject;
public class SimpleSerializingCallback extends
DefaultParsetreeReconstructorCallback {
static final Logger logger = Logger.getLogger(SimpleSerializingCallback.class);
static final Logger logger = Logger
.getLogger(SimpleSerializingCallback.class);
@Inject
protected IValueConverterService converterService;
@ -49,22 +48,11 @@ public class SimpleSerializingCallback extends
outputHasStarted = false;
out = output;
}
public void crossRefCall(IInstanceDescription current, CrossReference call) {
logger.debug("crossRefCall(" + call + ")");
Assignment ass = GrammarUtil.containingAssignment(call);
if (ass == null)
throw new IllegalStateException("Unassigned cross reference "
+ call);
Object object = current.get(ass.getFeature());
if (object instanceof EObject) {
EObject obj = (EObject) object;
// prepend(obj.eResource().getURIFragment(obj));
before(current, call);
append(obj.eResource().getURIFragment(obj));
}
throw new IllegalStateException("Can't serialize cross reference to "
+ object);
public void crossRefCall(IInstanceDescription current, CrossReference call,
EObject value) {
before(current, call);
append(value.eResource().getURIFragment(value));
}
public IValueConverterService getConverterService() {

View file

@ -8,8 +8,12 @@ import java.util.Map;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.IGrammarAccess;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.conversion.IValueConverterService;
import org.eclipse.xtext.parser.IAstFactory;
import org.eclipse.xtext.parsetree.reconstr.IInstanceDescription;
@ -19,10 +23,15 @@ import org.eclipse.xtext.service.Inject;
public abstract class AbstractParseTreeConstructor implements
IParseTreeConstructor {
protected enum AssignmentType {
KW, PRC, LRC, CR
};
public abstract class AbstractToken {
public class Solution {
private final InstanceDescription current;
private final IInstanceDescription current;
private final AbstractToken predecessor;
public Solution() {
@ -37,20 +46,20 @@ public abstract class AbstractParseTreeConstructor implements
this.predecessor = predecessor;
}
public Solution(final InstanceDescription current) {
public Solution(final IInstanceDescription current) {
super();
this.current = current;
this.predecessor = AbstractToken.this;
}
public Solution(InstanceDescription current,
public Solution(IInstanceDescription current,
AbstractToken predecessor) {
super();
this.current = current;
this.predecessor = predecessor;
}
public InstanceDescription getCurrent() {
public IInstanceDescription getCurrent() {
return current;
}
@ -61,13 +70,13 @@ public abstract class AbstractParseTreeConstructor implements
protected final static boolean IS_MANY = true;
protected final static boolean IS_REQUIRED = true;
protected final InstanceDescription current;
protected final IInstanceDescription current;
protected final boolean many;
protected Solution otherSolution;
protected final AbstractToken predecessor;
protected final boolean required;
public AbstractToken(InstanceDescription curr, AbstractToken pred,
public AbstractToken(IInstanceDescription curr, AbstractToken pred,
boolean many, boolean required) {
super();
this.current = curr;
@ -146,12 +155,12 @@ public abstract class AbstractParseTreeConstructor implements
return t1;
}
protected AbstractToken newInstance(InstanceDescription curr,
protected AbstractToken newInstance(IInstanceDescription curr,
AbstractToken pred) {
try {
Constructor<?> c = getClass().getConstructor(
getClass().getEnclosingClass(),
InstanceDescription.class, AbstractToken.class);
IInstanceDescription.class, AbstractToken.class);
return (AbstractToken) c.newInstance(
AbstractParseTreeConstructor.this, curr, pred);
} catch (SecurityException e) {
@ -182,34 +191,63 @@ public abstract class AbstractParseTreeConstructor implements
public abstract class ActionToken extends AbstractToken {
public ActionToken(InstanceDescription curr, AbstractToken pred,
public ActionToken(IInstanceDescription curr, AbstractToken pred,
boolean many, boolean required) {
super(curr, pred, many, required);
}
}
public abstract class AlternativeToken extends AbstractToken {
public abstract class AlternativesToken extends AbstractToken {
public AlternativeToken(InstanceDescription curr, AbstractToken pred,
protected boolean first = true;
public AlternativesToken(IInstanceDescription curr, AbstractToken pred,
boolean many, boolean required) {
super(curr, pred, many, required);
}
protected boolean activateNextSolution() {
if (first) {
first = false;
return true;
}
return false;
}
}
public abstract class AssignmentToken extends AbstractToken {
protected AbstractElement element;
protected Object value;
protected AssignmentType type;
public AssignmentToken(InstanceDescription curr, AbstractToken pred,
public AssignmentToken(IInstanceDescription curr, AbstractToken pred,
boolean many, boolean required) {
super(curr, pred, many, required);
}
public void executeCallback(IParseTreeConstructorCallback callback) {
if (type != null)
switch (type) {
case KW:
callback.keywordCall(current, (Keyword) element);
return;
case PRC: /* noting to do for parser rule calls */
return;
case LRC:
callback.lexerRuleCall(current, (RuleCall) element, value);
return;
case CR:
callback.crossRefCall(current, (CrossReference) element,
(EObject) value);
return;
}
}
}
public abstract class GroupToken extends AbstractToken {
public GroupToken(InstanceDescription curr, AbstractToken pred,
public GroupToken(IInstanceDescription curr, AbstractToken pred,
boolean many, boolean required) {
super(curr, pred, many, required);
}
@ -218,7 +256,7 @@ public abstract class AbstractParseTreeConstructor implements
public abstract class KeywordToken extends AbstractToken {
public KeywordToken(InstanceDescription curr, AbstractToken pred,
public KeywordToken(IInstanceDescription curr, AbstractToken pred,
boolean many, boolean required) {
super(curr, pred, many, required);
}
@ -227,7 +265,7 @@ public abstract class AbstractParseTreeConstructor implements
public abstract class RuleCallToken extends AbstractToken {
public RuleCallToken(InstanceDescription curr, AbstractToken pred,
public RuleCallToken(IInstanceDescription curr, AbstractToken pred,
boolean many, boolean required) {
super(curr, pred, many, required);
}
@ -248,7 +286,7 @@ public abstract class AbstractParseTreeConstructor implements
@Inject
private IGrammarAccess grammar;
protected final InstanceDescription getDescr(EObject obj) {
protected final IInstanceDescription getDescr(EObject obj) {
return new InstanceDescription(this, obj);
}

View file

@ -29,23 +29,33 @@ public class InstanceDescription implements IInstanceDescription {
*/
public AbstractParseTreeConstructor parseTreeConstr;
/* (non-Javadoc)
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#isInstanceOf(java.lang.String)
/*
* (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)
/*
* (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)
/*
* (non-Javadoc)
*
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#getDelegate()
*/
public EObject getDelegate() {
@ -55,13 +65,16 @@ public class InstanceDescription implements IInstanceDescription {
public EObject described;
public Map<String, Integer> featureConsumedCounter = new HashMap<String, Integer>();
public InstanceDescription(AbstractParseTreeConstructor abstractInternalParseTreeConstructor, EObject described) {
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();
EList<EStructuralFeature> features = described.eClass()
.getEAllStructuralFeatures();
for (EStructuralFeature f : features) {
Integer integer = 0;
if (described.eIsSet(f)) {
@ -75,15 +88,15 @@ public class InstanceDescription implements IInstanceDescription {
}
}
private InstanceDescription(AbstractParseTreeConstructor abstractInternalParseTreeConstructor, EObject described, Map<String, Integer> featureConsumedCounter) {
private InstanceDescription(
AbstractParseTreeConstructor abstractInternalParseTreeConstructor,
EObject described, Map<String, Integer> featureConsumedCounter) {
super();
this.parseTreeConstr = abstractInternalParseTreeConstructor;
this.described = described;
this.featureConsumedCounter = featureConsumedCounter;
}
@Override
public String toString() {
List<String> l = new ArrayList<String>();
@ -122,9 +135,13 @@ public class InstanceDescription implements IInstanceDescription {
featureConsumedCounter.put(feature, counter - 1);
return get;
}
/* (non-Javadoc)
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#get(java.lang.String)
/*
* (non-Javadoc)
*
* @see
* org.eclipse.xtext.parsetree.impl.IInstanceDescription#get(java.lang.String
* )
*/
public Object get(String feature) {
Integer counter = lazyGet(feature);
@ -163,14 +180,20 @@ public class InstanceDescription implements IInstanceDescription {
return described.eClass().getEStructuralFeature(feature);
}
/* (non-Javadoc)
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#isConsumable(java.lang.String)
/*
* (non-Javadoc)
*
* @see
* org.eclipse.xtext.parsetree.impl.IInstanceDescription#isConsumable(java
* .lang.String)
*/
public boolean isConsumable(String feature) {
return lazyGet(feature) > 0;
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.eclipse.xtext.parsetree.impl.IInstanceDescription#isConsumed()
*/
public boolean isConsumed() {
@ -182,21 +205,25 @@ public class InstanceDescription implements IInstanceDescription {
}
public IInstanceDescription createClone() {
return new InstanceDescription(this.parseTreeConstr, described, new HashMap<String, Integer>(featureConsumedCounter));
return new InstanceDescription(this.parseTreeConstr, described,
new HashMap<String, Integer>(featureConsumedCounter));
}
public int getConsumed(String feature) {
EStructuralFeature feature2 = described.eClass().getEStructuralFeature(feature);
EStructuralFeature feature2 = described.eClass().getEStructuralFeature(
feature);
if (feature2.isMany()) {
return ((Collection<?>)described.eGet(feature2)).size()-featureConsumedCounter.get(feature);
return ((Collection<?>) described.eGet(feature2)).size()
- featureConsumedCounter.get(feature);
}
return 1-featureConsumedCounter.get(feature);
return 1 - featureConsumedCounter.get(feature);
}
public String uniqueStateString() {
StringBuffer buff = new StringBuffer();
buff.append(getDelegate());
List<String> features = new ArrayList<String>(featureConsumedCounter.keySet());
List<String> features = new ArrayList<String>(featureConsumedCounter
.keySet());
Collections.sort(features);
for (String f : features) {
buff.append(f).append(featureConsumedCounter.get(f));
@ -204,4 +231,37 @@ public class InstanceDescription implements IInstanceDescription {
return buff.toString();
}
public IInstanceDescription cloneAndConsume(String feature) {
InstanceDescription inst = new InstanceDescription(
this.parseTreeConstr, described, new HashMap<String, Integer>(
featureConsumedCounter));
inst.featureConsumedCounter.put(feature, inst.lazyGet(feature) - 1);
return inst;
}
public Object getConsumable(String feature, boolean allowDefault) {
EStructuralFeature f = getFeature(feature);
if (f != null
&& (isConsumable(feature) || (allowDefault && !f.isMany()))) {
Integer counter = lazyGet(feature);
Object get = described.eGet(f);
if (f.isMany()) {
List<?> list = (List<?>) get;
get = list.get(counter - 1);
}
return get;
}
return null;
}
public boolean isConsumedWithLastConsumtion(String feature) {
for (Entry<String, Integer> e : featureConsumedCounter.entrySet()) {
Integer i = (e.getKey().equals(feature)) ? e.getValue() - 1 : e
.getValue();
if (i > 0)
return false;
}
return true;
}
}

View file

@ -11,7 +11,6 @@ package org.eclipse.xtext.parsetree.reconstr;
import java.io.ByteArrayOutputStream;
import java.util.Collections;
import org.apache.log4j.Logger;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.parsetree.NodeUtil;
import org.eclipse.xtext.testlanguages.SimpleExpressionsStandaloneSetup;
@ -19,8 +18,6 @@ import org.eclipse.xtext.tests.AbstractGeneratorTest;
import org.eclipse.xtext.util.EmfFormater;
public class SimpleReconstrTest extends AbstractGeneratorTest {
private static final Logger logger = Logger.getLogger(SimpleReconstrTest.class);
public void testSimple1() throws Exception {
String model = "a b";
@ -44,10 +41,10 @@ public class SimpleReconstrTest extends AbstractGeneratorTest {
private String parseAndSerialize(String model) throws Exception {
EObject result = (EObject) getModel(model);
logger.debug(EmfFormater.objToStr(result, ""));
logger.debug(EmfFormater.objToStr(NodeUtil.getRootNode(result),
System.out.println(EmfFormater.objToStr(result, ""));
System.out.println(EmfFormater.objToStr(NodeUtil.getRootNode(result),
""));
logger.debug(EmfFormater.objToStr(NodeUtil.getRootNode(result)
System.out.println(EmfFormater.objToStr(NodeUtil.getRootNode(result)
.getLeafNodes(), ""));
IParseTreeConstructor con = getParseTreeConstructor();
@ -72,6 +69,16 @@ public class SimpleReconstrTest extends AbstractGeneratorTest {
String model = "2 45";
assertEquals(model, parseAndSerialize(model));
}
public void testSimpleTwoNumbersWithDefault() throws Exception {
String model = "0 45";
assertEquals(model, parseAndSerialize(model));
}
public void testSimpleTwoNumbersWithDefault2() throws Exception {
String model = "0 45 # 0 # 1 # 2";
assertEquals(model, parseAndSerialize(model));
}
public void testSimpleManyStrings1() throws Exception {
String model = "= 'xxx' 'yyy'";
@ -83,6 +90,24 @@ public class SimpleReconstrTest extends AbstractGeneratorTest {
assertEquals(model, parseAndSerialize(model));
}
public void testSimpleAlternativeAssignment1() throws Exception {
String model = "#2 mykeyword1";
assertEquals(model, parseAndSerialize(model));
}
// FIXME: this depends on
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=250313
// public void testSimpleAlternativeAssignment2() throws Exception {
// String model = "#2 'str'";
// assertEquals(model, parseAndSerialize(model));
// }
// FIXME: make this work
// public void testCrossRef() throws Exception {
// String model = "type A extends B type B extends A";
// assertEquals(model, parseAndSerialize(model));
// }
@Override
protected void setUp() throws Exception {
with(SimpleReconstrTestStandaloneSetup.class);

View file

@ -13,7 +13,7 @@ Op returns Expression:
Term ({Op.values+=current} values+=Term)*;
Term returns Expression:
Atom | TwoNumbers | ManyStrings | Parens;
Atom | TwoNumbers | ManyStrings | Parens | Type | Ref2;
Atom:
name=ID;
@ -22,9 +22,15 @@ Parens returns Expression:
'(' Op ')' em='!'?;
TwoNumbers:
num1=INT num2=INT;
ManyStrings: '=' (str1+=STRING)* str2+=STRING;
num1=INT num2=INT ('#' num3+=INT)*;
ManyStrings:
'=' (str1+=STRING)* str2+=STRING;
Type :
'type' name=ID 'extends' ^extends=[Type];
Ref2:
'#2' ref2=('mykeyword1' | STRING | 'mykeyword2') ;