Creating Cross-Reference between XExpression and XVariableDeclaration outside of XBlockExpression [message #1726279] |
Fri, 11 March 2016 01:11 |
Larry LeBron Messages: 124 Registered: October 2015 |
Senior Member |
|
|
In my grammar, I am extending Xbase and using both XVariableDeclaration and XExpression, but I unfortunately need to work outside of XBlockExpression due to language design constraints.
I have everything working without errors, and my XExpressions can reference variables declared in my XVariableDeclarations, but the reference is occurring only at the level of the inferred class.
My variable declarations always have the warning: "the value of local variable is not used", even if they're used in an XExpression. Additionally, I do not get context assist recommendations including the variable declaration when writing an XExpression where the variable declaration should be in scope. Lastly, if I select "go to declaration" from inside an XExpression in Eclipse, instead of taking me to the variable declaration, it takes me to the name of the entity which is inferred as a class to contain the variable declaration and expression.
Any advice on the best way to solve this? I'm assuming it requires some bit of customizing scope, but there seem to be a few places to do that. What is the best practice? Thanks!
If it helps, here is a grammar, inferrer and a bit of sample code demonstrating the issue. I've made a small project solely to demonstrate this. I'll upload it with this post, in case that's helpful. The file extension is .xvartest
Here is some sample code. In this example, the first "x" is the variable declaration, and the second x is a reference to this declaration from an XExpression. There are no errors, but all of the issues I mentioned above exist.
Example:
entity myEnt {
var x;
exp x;
}
Here is the generated class for that:
public class myEnt {
private Object x;
public Object component2() {
return this.x;
}
}
Here is the grammar:
grammar org.xtext.example.XvarTest with org.eclipse.xtext.xbase.Xbase
generate xvarTest "http://www.xtext.org/example/XvarTest"
Model:
entities += Entity*
;
Entity:
'entity' name=ID '{'
components += EntityComponent+
'}'
;
EntityComponent:
VarDecl | ExpressionComponent
;
VarDecl:
decl=XVariableDeclaration';'
;
ExpressionComponent:
'exp' exp=XExpression ';'
;
Here is the inferrer for Entity:
def void inferEntity(Entity entity, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(entity.toClass(entity.name)[
var componentNum = 0
for (component : entity.components) {
componentNum++
if (component instanceof VarDecl) {
val varDecl = component as VarDecl
val decl = varDecl.decl as XVariableDeclaration
members += entity.toField(decl.name, decl.type) [
decl.right
]
} else if (component instanceof ExpressionComponent) {
val exprComp = component as ExpressionComponent
val expr = exprComp.exp
members += entity.toMethod("component"+componentNum, typeRef(Object)) [
body=expr
]
}
}
])
}
-
Attachment: xvartest.zip
(Size: 2.23MB, Downloaded 123 times)
|
|
|
Re: Creating Cross-Reference between XExpression and XVariableDeclaration outside of XBlockExpressio [message #1726287 is a reply to message #1726279] |
Fri, 11 March 2016 05:46 |
|
why xvariabledeclaration?!?
NotXVariableDeclaration:
{NotXVariableDeclaration}
(writeable?='var'|'val') (=>(type=JvmTypeReference name=ValidID) | name=ValidID) ('=' right=XExpression)?;
val decl = varDecl.decl as NotXVariableDeclaration
members += decl.toField(decl.name, decl.type?:inferredType) [
initializer = decl.right
]
you dont get any completion cause xtext does not know any context if you write simply exp
you could try to workaround this but i dont know if this will help
ExpressionComponent:
exp=MyXBlockExpression
;
MyXBlockExpression returns xbase::XExpression:
{xbase::XBlockExpression}
'exp' expressions+=XExpressionOrVarDeclaration ";";
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
Re: Creating Cross-Reference between XExpression and XVariableDeclaration outside of XBlockExpressio [message #1726303 is a reply to message #1726287] |
Fri, 11 March 2016 08:53 |
Larry LeBron Messages: 124 Registered: October 2015 |
Senior Member |
|
|
Thanks for the recommendation. Switching to a custom implementation of variable declaration did the trick. Makes sense, since the validator warning was specifically tied to XVariableDeclaration.
As far as the context goes, unfortunately that workaround didn't seem to work off the bat.
There are two pieces to this:
- Having Eclipse's "open declaration" jump to the variable declaration instead of jumping to the entity name
- Populating content assist for exp with varDecl names
As far as getting "open declaration" to work, any hint at what state would need to be established to get a varDecl reference from an expression working as a "true" reference?
It looks like implementing this in the UI ProposalProvider works to get the variable declaration added in the content assist, though I'm not sure if it's the best implementation:
override completeExpressionComponent_Exp(EObject expressionComponent, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
/* No proposal */
if (!(expressionComponent instanceof ExpressionComponent) ) {
return;
}
val entity = (expressionComponent as ExpressionComponent).eContainer;
(entity as Entity).components.forEach [
if (it instanceof VarDecl) {
val decl = it as VarDecl
acceptor.accept (
createCompletionProposal (
decl.name,
decl.name,
null,
context
)
)
}
]
}
|
|
|
|
|
|
Re: Creating Cross-Reference between XExpression and XVariableDeclaration outside of XBlockExpressio [message #1726609 is a reply to message #1726373] |
Tue, 15 March 2016 05:24 |
Larry LeBron Messages: 124 Registered: October 2015 |
Senior Member |
|
|
A small follow-up on this.
With your suggested grammar, I do get content assist for the ExpressionComponent, which is great, but I do not for the VarDecl.
A reminder of that grammar (which you proposed below):
VarDecl:
{VarDecl}
(writeable?='var'|'val') (=>(type=JvmTypeReference name=ValidID) | name=ValidID) ('=' right=XExpression)?;
ExpressionComponent:
exp=MyXBlockExpression
;
MyXBlockExpression returns xbase::XExpression:
{xbase::XBlockExpression}
'exp' expressions+=XExpressionOrVarDeclaration ";";
So, following your pattern, I tried making this change, assuming that if both used the "MyXBlockExpression" then everything would work:
VarDecl:
{VarDecl}
(writeable?='var'|'val') (=>(type=JvmTypeReference name=ValidID) | name=ValidID) ('=' right=MyXBlockExpression)? ';' ;
ExpressionComponent:
'exp' exp=MyXBlockExpression ';'
;
MyXBlockExpression returns xbase::XExpression:
{xbase::XBlockExpression}
expressions+=XExpression;
This compiles fine, but I lose partial functionality of the content assist. When I first request proposals for the MyXBlockExpression piece of the grammar, I get no concrete proposals. However, once I've begun an XExpression, then content assist works.
For example:
Entity ent {
var String s = "test";
exp [content assist at this point does not include 's'] // content assist request 1
exp "hello" + [content assist this point DOES include 's'] // content assist request 2
}
So, it seems like, at content assist request 1, the parser has not fully entered the MyXBlockExpression rule, or something of that nature.
I tried this experimental alteration of the grammar, making a dedicated XBlockExpression rule for both varDecl and expressionComponent, and everything works, but it's not as elegant and won't work for all situations:
VarDecl:
{VarDecl}
(writeable?='var'|'val') (=>(type=JvmTypeReference name=ValidID) | name=ValidID) (right=MyXBlockAssignment)? ;
MyXBlockAssignment returns xbase::XExpression:
{xbase::XBlockExpression}
'=' expressions+=XExpression ';';
ExpressionComponent:
exp=MyXBlockExpression
;
MyXBlockExpression returns xbase::XExpression:
{xbase::XBlockExpression}
'exp' expressions+=XExpression ';';
Is there a way to make my first example work? Perhaps I'm just missing something simple, like a specific use of "=>" ?
|
|
|
|
Powered by
FUDForum. Page generated in 0.03738 seconds