Context aware grammar help [message #1793041] |
Sun, 29 July 2018 11:38  |
Eclipse User |
|
|
|
Hi,
I'm trying to implement a conditions DSL which would looks something like this:
select <domain specific class> where <property> <condition> <literal> [(AND|OR) <property> <condition> <literal>]*
So in the end it should be something like this:
select person where name == "Mykola" AND address.city == "L'viv"
or this:
select location where title != "Office" OR cooridinates.latitude > 150
etc.
The problem here is to make parsing and autocompletion code aware of the context, which is <domain specific class> - so that it would only allow (and autocomplete) the properties of that domain specific class. Also those properties might be of different types themselves, which are either primitive (string, int, float) or sub-objects.
What would be the simplest/best way to implement this?
Since in the end I'm going to work with Java classes representing DSL classes, I thought that maybe Xbase is the way - but first of all I didn't find how to make it import particular classes into DSL, and then it also seems to have a lot of things that I don't want to end up in my DSL (it should be limited so it would be secure - so that no vulnerabilities like code injection would be possible).
Plus it seems to be rather complex and very hard to wrap one's head around, at least in the beginning.
|
|
|
|
Re: Context aware grammar help [message #1793102 is a reply to message #1793080] |
Tue, 31 July 2018 04:33   |
Eclipse User |
|
|
|
Thanks, Christian, for your answer.
However, it's not clear to me how scoping alone can help.
The question is - how can I define a model outside of a DSL to be used inside of a DSL (e.g. classes like person or location with their own properties that may hold instances of different classes etc). The examples of scoping I've seen so far (in official documentation, speech videos, books etc - I've checked a lot of them) are mostly focused on cases when model is defined within DSL, and then it is (cross-)referenced in same DSL.
But how can I define model externally? Should I use Ecore for that? Or can I somehow import POJO classes into DSL to be used? Is it at all possible implement some completion/scoping using reflection on POJO classes, and if it is - where do I even start?
If it is not possible - what are the alternatives? Only Ecore? How would I add an Ecore model to an Xtext project? Seems I have to modify workflow (mwe2) file to generate model from .ecore (or is it .genmodel?) file, but what else has to be done?
I'm sorry for so many questions, but the issue seems quite confusing and much more complex than I've originally anticipated.
[Updated on: Tue, 31 July 2018 04:35] by Moderator
|
|
|
|
|
|
|
|
|
|
|
Re: Context aware grammar help [message #1793516 is a reply to message #1793131] |
Thu, 09 August 2018 08:17   |
Eclipse User |
|
|
|
I've run into a problem with the proposal provider when implementing completion for properties and subproperties of some entity.
Here's the example DSL text of what I'm trying to achieve:
for User as user find @user.name == "Mykola" && @user.address.city == "Lviv"
In my grammar I have a code like this for "fully qualified names":
Rule: 'for' entityRefDef=EntityReferenceDefinition 'find' conditions=Conditions;
FQN:
'@' entityReference=[EntityReferenceDefinition|EntityReferenceName] ('.' property+=ID)*;
EntityReferenceDefinition:
entityType=ID 'as' name= EntityReferenceName;
EntityReferenceName:
ID;
Conditions:
... bunch of logical conditions and comparison related code with left factoring etc
In my content proposal provider I've added something like this:
@Inject EntityMetadataProvider metaProvider
override dispatch createProposals(RuleCall ruleCall, ContentAssistContext context,
IIdeContentProposalAcceptor acceptor) {
if (context.currentModel instanceof FQN && ruleCall.rule.name == "ID" &&
ruleCall.eContainer instanceof Assignment && (ruleCall.eContainer as Assignment).feature == "property") {
val fqn = context.currentModel as FQN;
if (fqn.entityReference !== null) {
for (String propertyName : metaProvider.getPropertyNames(fqn.entityReference.entityType, fqn.property)) {
proposeString(propertyName, acceptor);
}
}
}
}
def protected proposeString(String proposalText, IIdeContentProposalAcceptor acceptor) {
val proposal = new ContentAssistEntry();
proposal.proposal = proposalText
acceptor.accept(proposal, proposalPriorities.getDefaultPriority(proposal));
}
The EntityMetadataProvider provides lists of properties given entity type (e.g. "User") and property path (["name", "address"] for empty property path, ["city", "street", "building", ...] for "address" etc - supporting any arbitrary depth).
It almost works, except for cases when I try to do completion when part of the text is already added.
E.g. for this text
for User as user find @user.name == "Mykola" && @user.address.city == "Lviv"
placing cursor after "@user." should provide completions ["name", "address"]. But it only does so if no property is already written afterwards (e.g. for input like "for User as user find @user." or "for User as user find @user. && @user.address.city == "Lviv"" if cursor is placed after first occurrence of "@user.", the one followed by a space and &&).
If I place cursor after "@user." in text like "... @user.address" I get completions ["city", "street", "building", ...] because (context.currentModel as FQN).property already contains address - even though I moved cursor behind it and I'm trying to replace it.
First of all, I haven't found any way to figure out which of (context.currentModel as FQN).property values are behind the cursor, and which are ahead of it.
Second, I'm not sure if implementing completion this way makes sense at all - or there is a simpler or more correct way to implement the same functionality.
In future I also want to add corresponding validation - so only properties that are appearing in completion are allowed.
So in view of this, is there a better approach for me to implement this completion? Or if there isn't - how can this particular issue be fixed?
[Updated on: Thu, 09 August 2018 08:21] by Moderator
|
|
|
|
|
Re: Context aware grammar help [message #1793565 is a reply to message #1793558] |
Fri, 10 August 2018 05:28  |
Eclipse User |
|
|
|
P.S. I'm currently working with this option. This allows me to have hierarchy of Property objects, so I could walk up the tree to check parent properties only.
Seems like a viable fix, but I had to rewrite completion code with regard to changes in generated model:
Rule: 'for' entityRefDef=EntityReferenceDefinition 'find' conditions=Conditions;
FQN:
'@' entityReference=[EntityReferenceDefinition|EntityReferenceName] ('.' property=Property)?;
Property:
name=ID ('.' property=Property)?
EntityReferenceDefinition:
entityType=ID 'as' name= EntityReferenceName;
EntityReferenceName:
ID;
Conditions:
... bunch of logical conditions and comparison related code with left factoring etc
[Updated on: Fri, 10 August 2018 05:29] by Moderator
|
|
|
Powered by
FUDForum. Page generated in 0.07584 seconds