|
Re: boolean assignment operator not working as expected [message #1808612 is a reply to message #1808611] |
Thu, 27 June 2019 20:01 |
|
hi, how do you test that? the following gives false to me:
class MyDslParsingTest {
@Inject
ParseHelper<LogicalRealRangeConstraint> parseHelper
@Test
def void loadModel() {
val result = parseHelper.parse('''
rrc x "y" (1:1)
''')
Assertions.assertNotNull(result)
val errors = result.eResource.errors
Assertions.assertTrue(errors.isEmpty, '''Unexpected errors: «errors.join(", ")»''')
println(result.lowerBoundInclusive)
println(result.upperBoundInclusive)
}
}
do you have a custom manual metamodel with different default values?
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
Re: boolean assignment operator not working as expected [message #1808613 is a reply to message #1808612] |
Thu, 27 June 2019 20:06 |
Steve Hickman Messages: 56 Registered: August 2017 |
Member |
|
|
There is a custom metamodel that I can't change (it is supplied to me). The defaults in it are true:
/**
*/
package face.v30.face.datamodel.logical.impl;
import face.v30.face.datamodel.logical.LogicalPackage;
import face.v30.face.datamodel.logical.RealRangeConstraint;
import java.lang.Boolean;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Real Range Constraint</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* </p>
* <ul>
* <li>{@link face.v30.face.datamodel.logical.impl.RealRangeConstraintImpl#getLowerBound <em>Lower Bound</em>}</li>
* <li>{@link face.v30.face.datamodel.logical.impl.RealRangeConstraintImpl#getUpperBound <em>Upper Bound</em>}</li>
* <li>{@link face.v30.face.datamodel.logical.impl.RealRangeConstraintImpl#isLowerBoundInclusive <em>Lower Bound Inclusive</em>}</li>
* <li>{@link face.v30.face.datamodel.logical.impl.RealRangeConstraintImpl#isUpperBoundInclusive <em>Upper Bound Inclusive</em>}</li>
* </ul>
*
* @generated
*/
public class RealRangeConstraintImpl extends RealConstraintImpl implements RealRangeConstraint {
/**
* The default value of the '{@link #getLowerBound() <em>Lower Bound</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getLowerBound()
* @generated
* @ordered
*/
protected static final float LOWER_BOUND_EDEFAULT = 0.0F;
/**
* The cached value of the '{@link #getLowerBound() <em>Lower Bound</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getLowerBound()
* @generated
* @ordered
*/
protected float lowerBound = LOWER_BOUND_EDEFAULT;
/**
* The default value of the '{@link #getUpperBound() <em>Upper Bound</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getUpperBound()
* @generated
* @ordered
*/
protected static final float UPPER_BOUND_EDEFAULT = 0.0F;
/**
* The cached value of the '{@link #getUpperBound() <em>Upper Bound</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getUpperBound()
* @generated
* @ordered
*/
protected float upperBound = UPPER_BOUND_EDEFAULT;
/**
* The default value of the '{@link #isLowerBoundInclusive() <em>Lower Bound Inclusive</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isLowerBoundInclusive()
* @generated
* @ordered
*/
protected static final boolean LOWER_BOUND_INCLUSIVE_EDEFAULT = true;
/**
* The cached value of the '{@link #isLowerBoundInclusive() <em>Lower Bound Inclusive</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isLowerBoundInclusive()
* @generated
* @ordered
*/
protected boolean lowerBoundInclusive = LOWER_BOUND_INCLUSIVE_EDEFAULT;
/**
* The default value of the '{@link #isUpperBoundInclusive() <em>Upper Bound Inclusive</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isUpperBoundInclusive()
* @generated
* @ordered
*/
protected static final boolean UPPER_BOUND_INCLUSIVE_EDEFAULT = true;
/**
* The cached value of the '{@link #isUpperBoundInclusive() <em>Upper Bound Inclusive</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isUpperBoundInclusive()
* @generated
* @ordered
*/
protected boolean upperBoundInclusive = UPPER_BOUND_INCLUSIVE_EDEFAULT;
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected RealRangeConstraintImpl() {
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return LogicalPackage.Literals.REAL_RANGE_CONSTRAINT;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public float getLowerBound() {
return lowerBound;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setLowerBound(float newLowerBound) {
float oldLowerBound = lowerBound;
lowerBound = newLowerBound;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND, oldLowerBound, lowerBound));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public float getUpperBound() {
return upperBound;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setUpperBound(float newUpperBound) {
float oldUpperBound = upperBound;
upperBound = newUpperBound;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND, oldUpperBound, upperBound));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean isLowerBoundInclusive() {
return lowerBoundInclusive;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setLowerBoundInclusive(boolean newLowerBoundInclusive) {
boolean oldLowerBoundInclusive = lowerBoundInclusive;
lowerBoundInclusive = newLowerBoundInclusive;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND_INCLUSIVE, oldLowerBoundInclusive, lowerBoundInclusive));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean isUpperBoundInclusive() {
return upperBoundInclusive;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setUpperBoundInclusive(boolean newUpperBoundInclusive) {
boolean oldUpperBoundInclusive = upperBoundInclusive;
upperBoundInclusive = newUpperBoundInclusive;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND_INCLUSIVE, oldUpperBoundInclusive, upperBoundInclusive));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND:
return getLowerBound();
case LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND:
return getUpperBound();
case LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND_INCLUSIVE:
return isLowerBoundInclusive();
case LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND_INCLUSIVE:
return isUpperBoundInclusive();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eSet(int featureID, Object newValue) {
switch (featureID) {
case LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND:
setLowerBound((Float)newValue);
return;
case LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND:
setUpperBound((Float)newValue);
return;
case LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND_INCLUSIVE:
setLowerBoundInclusive((Boolean)newValue);
return;
case LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND_INCLUSIVE:
setUpperBoundInclusive((Boolean)newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eUnset(int featureID) {
switch (featureID) {
case LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND:
setLowerBound(LOWER_BOUND_EDEFAULT);
return;
case LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND:
setUpperBound(UPPER_BOUND_EDEFAULT);
return;
case LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND_INCLUSIVE:
setLowerBoundInclusive(LOWER_BOUND_INCLUSIVE_EDEFAULT);
return;
case LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND_INCLUSIVE:
setUpperBoundInclusive(UPPER_BOUND_INCLUSIVE_EDEFAULT);
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND:
return lowerBound != LOWER_BOUND_EDEFAULT;
case LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND:
return upperBound != UPPER_BOUND_EDEFAULT;
case LogicalPackage.REAL_RANGE_CONSTRAINT__LOWER_BOUND_INCLUSIVE:
return lowerBoundInclusive != LOWER_BOUND_INCLUSIVE_EDEFAULT;
case LogicalPackage.REAL_RANGE_CONSTRAINT__UPPER_BOUND_INCLUSIVE:
return upperBoundInclusive != UPPER_BOUND_INCLUSIVE_EDEFAULT;
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public String toString() {
if (eIsProxy()) return super.toString();
StringBuilder result = new StringBuilder(super.toString());
result.append(" (lowerBound: ");
result.append(lowerBound);
result.append(", upperBound: ");
result.append(upperBound);
result.append(", lowerBoundInclusive: ");
result.append(lowerBoundInclusive);
result.append(", upperBoundInclusive: ");
result.append(upperBoundInclusive);
result.append(')');
return result.toString();
}
} //RealRangeConstraintImpl
|
|
|
Re: boolean assignment operator not working as expected [message #1808614 is a reply to message #1808613] |
Thu, 27 June 2019 20:09 |
|
maybe you can use a custom DefaultEcoreElementsFactory
and do something like
public class MyDslDefaultEcoreElementFactory extends DefaultEcoreElementFactory {
@Override
public EObject create(EClassifier classifier) {
EObject created = super.create(classifier);
if (created instanceof LogicalRealRangeConstraint) {
((LogicalRealRangeConstraint)created).setLowerBoundInclusive(false);
((LogicalRealRangeConstraint)created).setUpperBoundInclusive(false);
}
return created;
}
}
if this has bad side effects (e.g. on serialization needs to be tested, maybe there customization is needed too)
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
Re: boolean assignment operator not working as expected [message #1808619 is a reply to message #1808617] |
Thu, 27 June 2019 20:28 |
|
maybe you can use a different grammar pattern + a value converter
generate myDsl "http://www.xtext.org/example/mydsl1/MyDsl"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
LogicalRealRangeConstraint /*hidden (WS)*/:
'rrc' name=ID (description=STRING)? lowerBoundInclusive=LOWER_BOUND_INCLUSIVE
lowerBound=INT? ':' upperBound=INT?
upperBoundInclusive=UPPER_BOUND_INCLUSIVE;
LOWER_BOUND_INCLUSIVE returns ecore::EBoolean:
"(" | "[";
UPPER_BOUND_INCLUSIVE returns ecore::EBoolean:
")" | "]";
package org.xtext.example.mydsl1;
import org.eclipse.xtext.common.services.DefaultTerminalConverters;
import org.eclipse.xtext.conversion.IValueConverter;
import org.eclipse.xtext.conversion.ValueConverter;
import org.eclipse.xtext.conversion.ValueConverterException;
import org.eclipse.xtext.nodemodel.INode;
public class MyDslValueConverters extends DefaultTerminalConverters {
@ValueConverter(rule = "LOWER_BOUND_INCLUSIVE")
public IValueConverter<Boolean> LOWER_BOUND_INCLUSIVE() {
return new IValueConverter<Boolean>() {
@Override
public Boolean toValue(String string, INode node) throws ValueConverterException {
return "[".equals(string);
}
@Override
public String toString(Boolean value) throws ValueConverterException {
if (Boolean.TRUE.equals(value)) {
return "[";
}
return "(";
}
};
}
@ValueConverter(rule = "UPPER_BOUND_INCLUSIVE")
public IValueConverter<Boolean> UPPER_BOUND_INCLUSIVE() {
return new IValueConverter<Boolean>() {
@Override
public Boolean toValue(String string, INode node) throws ValueConverterException {
return "]".equals(string);
}
@Override
public String toString(Boolean value) throws ValueConverterException {
if (Boolean.TRUE.equals(value)) {
return "]";
}
return ")";
}
};
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
Re: boolean assignment operator not working as expected [message #1808632 is a reply to message #1808621] |
Fri, 28 June 2019 05:25 |
Ed Willink Messages: 7670 Registered: July 2009 |
Senior Member |
|
|
Hi
I've hit this problem too when I've tried to use a default-true Boolean literal with Xtext. I've had the flexibility to change the metamodel / model reader to workaround the problem. Your less flexible case makes clear that this is arguably an Xtext bug....
An unsettable EMF Boolean has three values internally, true, false, unset. The unset value is only detectable by using eIsSet().
Once a default is supplied, the external view of the Boolean is explicitly-true, explicitly-false, implicitly-default.
The Xtext grammar supports only two values. explicitly-true, implicitly-default.
With a false default, the Xtext grammar gives explicitly-true, implicitly-false which is useable.
With a true default, the Xtext grammar gives explicitly-true, implicitly-true which is not useable.
Therefore the Xtext parser should replace true assignments to Booleans that are default true, with false assignments on all alternative control paths. Or Xtext should support three values ?= for explicitly true, ~= for explicitly false, nothing for default.
(The problem just gets worse if the EMF Boolean is not-unsettable removing the internally unset value).
Regards
Ed Willink
|
|
|
|
Powered by
FUDForum. Page generated in 0.05762 seconds