Linker does not check type [message #870533] |
Tue, 08 May 2012 14:57 |
Reiner Hille Messages: 18 Registered: July 2009 |
Junior Member |
|
|
Hi all,
assume I have the following simple Java-like grammar:
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "www.xtext.org/example/mydsl/MyDsl"
Lib:
(classes+=Class)*;
Class:
'class' name=ID '{'
(member+=Member)*
'}';
Member:
Field | Method;
Field:
type=Type name=ID;
Method:
type=Type name=ID '(' ')' '{'
(statements+=Statement)*
'}';
Type:
'int';
Statement:
(VariableDeclaration | Selection) ';';
Selection:
object=[VariableDeclaration] '.' (member=[Field] | member=[Method] '(' ')');
VariableDeclaration:
type=[Class] name=ID;
Then I generate, run the target platform and test the editor for the grammar with following snippet:
class A {
int afield
int aMethod() {
}
int test () {
A var1;
var1.afield;
var1.aMethod;
var1.afield();
var1.aMethod();
}
}
There is no error marker shown. However, the grammar clearly requires a method to be called with parenthesis and fields without.
The linker simply resolved the references to the members "aMethod" and "afield" by name, ignoring the contraint in the grammar:
object=[VariableDeclaration] '.' (member=[Field] | member=[Method] '(' ')');
Of cause both, "Field" and "Method" inherit from the same EMF class "Member", thus the linker can set those "wrong" cross references.
The problem here happens in DefaultLinkingService.getLinkedObjects()
public List<EObject> getLinkedObjects(EObject context, EReference ref, INode node)
throws IllegalNodeException {
final EClass requiredType = ref.getEReferenceType();
if (requiredType == null)
return Collections.<EObject> emptyList();
final String crossRefString = getCrossRefNodeAsString(node);
if (crossRefString != null && !crossRefString.equals("")) {
if (logger.isDebugEnabled()) {
logger.debug("before getLinkedObjects: node: '" + crossRefString + "'");
}
final IScope scope = getScope(context, ref);
QualifiedName qualifiedLinkName = qualifiedNameConverter.toQualifiedName(crossRefString);
IEObjectDescription eObjectDescription = scope.getSingleElement(qualifiedLinkName);
if (logger.isDebugEnabled()) {
logger.debug("after getLinkedObjects: node: '" + crossRefString + "' result: " + eObjectDescription);
}
if (eObjectDescription != null)
return Collections.singletonList(eObjectDescription.getEObjectOrProxy());
}
return Collections.emptyList();
}
In the first line it only checks the required type from the ref's target type - which is in our case "Member".
Additionally it should also check the type that is given my the grammar, similar like the following pseudo-code:
if (node instanceof LeafNode) {
LeafNode memberLeafNode = (LeafNode) node;
EObject grammarElement = memberLeafNode.getGrammarElement();
if (grammarElement instanceof CrossReference) {
CrossReference xref = (CrossReference) grammarElement;
EClassifier classifier = xref.getType().getClassifier();
// TODO: Check if resolved EObject is instance of this classifier
}
}
I did a similar thing in a custom validator, but this was quire ugly, as the LeafNode is not directly accessable. And I think that Xtext could do this automatically. What do you think?
Reiner.
|
|
|
Re: Linker does not check type [message #870537 is a reply to message #870533] |
Tue, 08 May 2012 15:18 |
|
Hi Reiner,
it could be solved much easier:
grammar org.xtext.example.mydsl.MyDsl with
org.eclipse.xtext.common.Terminals
generate myDsl "www.xtext.org/example/mydsl/MyDsl"
Lib:
(classes+=Class)*;
Class:
'class' name=ID '{'
(member+=Member)*
'}';
Member:
Field | Method;
Field:
type=Type name=ID;
Method:
type=Type name=MethodDecl '{'
(statements+=Statement)*
'}';
Type:
'int';
Statement:
(VariableDeclaration | Selection) ';';
Selection:
object=[VariableDeclaration] '.' (member=[Field] |
member=[Method|MethodDecl]);
VariableDeclaration:
type=[Class] name=ID;
MethodDecl:
ID '(' ')'
;
Cheers,
Holger
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
|
|
|
|
Re: Linker does not check type [message #870705 is a reply to message #870544] |
Wed, 09 May 2012 12:01 |
|
With this grammar it should work. But nor you'll need a typesyteme. You
may have a look at xbase where all this is already solved in a common
way. BTW: You check is not valid in the case that the stuff with the
braches is solved.
grammar org.xtext.example.mydsl.MyDsl with
org.eclipse.xtext.common.Terminals
generate myDsl "www.xtext.org/example/mydsl/MyDsl"
Lib:
(classes+=Class)*;
Class:
'class' name=ID '{'
(member+=Member)*
'}';
Member:
Field | Method;
Field:
type=Type name=ID;
Method:
type=Type name=ID '{'
(statements+=Statement)*
'}';
Type:
'int';
Statement:
(VariableDeclaration | Selection) ';';
Selection:
object=[VariableDeclaration] '.' call=FeatureCall;
FeatureCall:
FieldCall | MethodCall
;
FieldCall:
field=[Field]
;
MethodCall:
method=[Method] => '('( args+=ID ("," args+=ID)*)? ')'
;
VariableDeclaration:
type=[Class] name=ID;
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
|
|
|
Re: Linker does not check type [message #871344 is a reply to message #870533] |
Sat, 12 May 2012 08:47 |
|
Hi Reiner
your grammar looks similar to the Featherweight Java I implemented in
Xtext, (the implementation is now an example in Xsemantics DSL,
http://xsemantics.sourceforge.net/xsemantics-documentation/FJ-example.html#FJ)
hope this helps
Lorenzo
On 05/08/2012 04:58 PM, Reiner Hille wrote:
> Hi all,
> assume I have the following simple Java-like grammar:
>
> grammar org.xtext.example.mydsl.MyDsl with
> org.eclipse.xtext.common.Terminals
>
> generate myDsl "www.xtext.org/example/mydsl/MyDsl"
>
> Lib:
> (classes+=Class)*;
>
> Class:
> 'class' name=ID '{'
> (member+=Member)*
> '}';
>
> Member:
> Field | Method;
>
> Field:
> type=Type name=ID;
>
> Method:
> type=Type name=ID '(' ')' '{'
> (statements+=Statement)*
> '}';
>
> Type:
> 'int';
>
> Statement:
> (VariableDeclaration | Selection) ';';
>
> Selection:
> object=[VariableDeclaration] '.' (member=[Field] | member=[Method] '('
> ')');
>
> VariableDeclaration:
> type=[Class] name=ID;
>
>
> Then I generate, run the target platform and test the editor for the
> grammar with following snippet:
>
> class A {
> int afield
> int aMethod() {
> }
>
> int test () {
> A var1;
> var1.afield;
> var1.aMethod;
> var1.afield();
> var1.aMethod();
> }
> }
>
>
> There is no error marker shown. However, the grammar clearly requires a
> method to be called with parenthesis and fields without.
> The linker simply resolved the references to the members "aMethod" and
> "afield" by name, ignoring the contraint in the grammar:
>
> object=[VariableDeclaration] '.' (member=[Field] | member=[Method] '('
> ')');
>
> Of cause both, "Field" and "Method" inherit from the same EMF class
> "Member", thus the linker can set those "wrong" cross references. The
> problem here happens in DefaultLinkingService.getLinkedObjects()
>
> public List<EObject> getLinkedObjects(EObject context, EReference ref,
> INode node)
> throws IllegalNodeException {
> final EClass requiredType = ref.getEReferenceType();
> if (requiredType == null)
> return Collections.<EObject> emptyList();
>
> final String crossRefString = getCrossRefNodeAsString(node);
> if (crossRefString != null && !crossRefString.equals("")) {
> if (logger.isDebugEnabled()) {
> logger.debug("before getLinkedObjects: node: '" + crossRefString + "'");
> }
>
> final IScope scope = getScope(context, ref);
> QualifiedName qualifiedLinkName =
> qualifiedNameConverter.toQualifiedName(crossRefString);
> IEObjectDescription eObjectDescription =
> scope.getSingleElement(qualifiedLinkName);
> if (logger.isDebugEnabled()) {
> logger.debug("after getLinkedObjects: node: '" + crossRefString + "'
> result: " + eObjectDescription);
> }
> if (eObjectDescription != null) return
> Collections.singletonList(eObjectDescription.getEObjectOrProxy());
> }
> return Collections.emptyList();
> }
>
> In the first line it only checks the required type from the ref's target
> type - which is in our case "Member".
> Additionally it should also check the type that is given my the grammar,
> similar like the following pseudo-code:
>
> if (node instanceof LeafNode) {
> LeafNode memberLeafNode = (LeafNode) node;
> EObject grammarElement = memberLeafNode.getGrammarElement();
> if (grammarElement instanceof CrossReference) {
> CrossReference xref = (CrossReference) grammarElement;
> EClassifier classifier = xref.getType().getClassifier(); // TODO: Check
> if resolved EObject is instance of this classifier
> }
> }
>
> I did a similar thing in a custom validator, but this was quire ugly, as
> the LeafNode is not directly accessable. And I think that Xtext could do
> this automatically. What do you think?
>
> Reiner.
--
Lorenzo Bettini, PhD in Computer Science, DI, Univ. Torino
ICQ# lbetto, 16080134 (GNU/Linux User # 158233)
HOME: http://www.lorenzobettini.it MUSIC: http://www.purplesucker.com
http://www.myspace.com/supertrouperabba
BLOGS: http://tronprog.blogspot.com http://longlivemusic.blogspot.com
http://www.gnu.org/software/src-highlite
http://www.gnu.org/software/gengetopt
http://www.gnu.org/software/gengen http://doublecpp.sourceforge.net
HOME: http://www.lorenzobettini.it
TDD Book: https://leanpub.com/tdd-buildautomation-ci
Xtext Book: https://www.packtpub.com/application-development/implementing-domain-specific-languages-xtext-and-xtend-second-edition
|
|
|
Powered by
FUDForum. Page generated in 0.03443 seconds