get tree root of different DSL file in same project for xtend validation - xtext

I have 2 different DSL. These are linked in their grammar, in such a way that "hobbies" defined in 1 DSL, can be referenced in the 2nd DSL. I want to have validation rule that all the Hobbies are referenced in the 2nd DSL.
How can I obtain all the defined hobbies of the first DSL in the validation file of the 2nd DSL?
The first DSL called "MyDsl.xtext" looks like:
'I' 'am' name=ID
greetings+=HelloGreeting* 'Hobbies' hobbies+=Hobbie+
('I_dont_like' detests+=[Hobbie|QualifiedName])?
;
Hobbie:
'eg' name=ID
;
HelloGreeting:
'Hello' person=[Person] '!'
;
The second DSL called "MyDsl1.xtext" looks like:
JustGreetings:
greetings+=HiGreeting* stuff=Stuff
;
HiGreeting:
'Hi' person=[imported::Person] '!'
;
Stuff:
'I_also_like_to_do:' hobbies+=[imported::Hobbie|QualifiedName]+
;
The validation I am trying to do in the validation file looks like:
import org.eclipse.xtext.validation.Check;
import org.xtext.example.mydsl.myDsl.Person
import org.xtext.example.mydsl1.myDsl1.Stuff
class MyDsl1Validator extends AbstractMyDsl1Validator {
public static val INVALID_NAME = 'invalidName'
boolean found
#Check
def checkWalking(Stuff stuffs) {
var myHobbies = stuffs.hobbies
var definedHobbies = getPersons().hobbies
for (i: 0..definedHobbies.size) {
found = false
for (j: 0..myHobbies.size) {
if (definedHobbies.get(i).name == myHobbies.get(j).name) {
found = true
}
}
if (found == false) {
error("you are missing hobbie" + myHobbies.get(i).name + '.', null)
}
}
}
}
Current result: Right now I can import the Person type in the imports, that gives no error, but i do not know how to get all the instances.
Expected Result:
I can get a list of Persons defined in the other DSL, and use it to compare.
Edit:
Example inputs:
definition.mydsl
I am A
Hello B !
Hobbies eg walking
usage.mydsl1
Hi A!
I_also_like_to_do: A.walking

Related

Counting repeated tokens in ANTLR4

I am writing a simple "language" in ANTLR4/JavaScript which can associate numbers to variables and print them. This works fine but after extending the print statement to take one or many variables I don't figure out how to get the count of them. (I am using a visitor, not listener, but am interested for both.)
Grammar:
print : 'print' ID (',' ID)* ';' ;
How do I find out how many ID tokens there are?
Currently I hacked something together as follows:
visitPrint( ctx ) {
let i = 0;
let c = undefined;
while( (c = ctx.ID(i)) ) {
let val = ctx.ID(i++).getText();
print( this.variables[val] );
}
}
Shouldn't there be a better way to do this, like some count() method?
Thanks for your response!
In your visitPrint method you get a PrintContext with a member ID(). This returns an array and you can simply use context.ID().length to get the ID count (note: no parameter).
If you create an id parser rule:
id
: ID
;
and then use this id rule in all other parser rules instead of the ID token, then you can override the visitId function:
visitId(ctx) {
// Check ctx.ID() here
}

How to eliminate duplicates in xtext

Test:
'Hai' name=ID*;
This is the parser rule.For this can we eliminate duplicates i.e., hai all all.
all is repeating many times .Now is there any way to eliminate duplicates in xtext
If you want to check duplicates in the local file you can adapt and rerun the workflow as follows
validator = {
composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
}
or write a manual validation (pseudo code, only one of 1000 possible variants)
public static val DUP_NAME = 'dupName'
#Check
def checkGreetingStartsWithCapital(Model model) {
val names = newHashSet
for (g : model.greetings) {
if (names.add(g.name)) {
error("duplicate" , g, MyDslPackage.Literals.GREETING__NAME, DUP_NAME)
}
}
}

How do I just create a parse tree with perl6 grammar?

I'm trying to create a grammar. Here's my code so far:
use Text::Table::Simple; # zef install Text::Table::Simple
my $desc = q:to"FIN";
record person
name string;
age int;
end-record
FIN
grammar rec {
token TOP { <ws>* 'record' \s+ <rec-name> <field-descriptors> <ws> 'end-record' <ws> }
token rec-name { \S+ }
token field-descriptors { <field-descriptor>* }
token field-descriptor { <ws>* <field-name> <ws>+ <field-type> <ws>* ';' }
token field-name { \S+ }
token field-type { <[a..z]>+ }
token ws { <[\r\n\t\ ]> }
}
class recActions {
method field-descriptors($/) { $/.make: $/; }
method field-descriptor($/) { $/.make: $/; }
method field-name($/) { $/.make: $/ }
method field-type($/) { $/.make: $/ }
}
my $r = rec.parse($desc, :actions(recActions));
#say $r;
my $inp = q:to"FIN";
adam 26
joe 23
mark 51
FIN
sub splitter($line) {
my #lst = split /\s+/, $line;
}
sub matrixify(&splitter, $data)
{
my #d = (split /\n/, (trim-trailing $data)).map( -> $x { splitter $x ; } );
##d.say;
#my #cols = <name age>;
#say lol2table(#cols, #d).join("\n");
#d;
}
#my #cols =<A B>;
#my #rows = ([1,2], [3,4]);
#say lol2table(#cols, #rows).join("\n");
my #m = matrixify &splitter, $inp;
sub tabulate($rec-desc, #matrix)
{
my $fds = $rec-desc<field-descriptors>;
#say %fds<field-name>;
say $fds;
my #cols = $rec-desc.<field-descriptors>.map( -> $fd { say $fd; $fd.<field-name> ; 1;} );
#say $rec-desc.<field-descriptors>;
#say #cols;
}
tabulate $r, #m ;
I really just want the grammar to create a tree of lists/hash tables from the input. The output from the code is:
「
name string;
age int;」
field-descriptor => 「
name string;」
ws => 「
」
ws => 「 」
field-name => 「name」
ws => 「 」
field-type => 「string」
field-descriptor => 「
age int;」
ws => 「
」
ws => 「 」
field-name => 「age」
ws => 「 」
ws => 「 」
field-type => 「int」
which looks fairly good. perl6 seems to be decoding the fact that field-descriptors is composed of multiple field-descriptor, but it doesn't actually seem to put them into a list. I can do say $fds;, but I can't do say $fds[0];. Why does the former "work", but the latter doesn't?
I must admit to having a fairly weak grasp of what's going on. Would I be better of using rules instead of tokens? Do I really need an actions class; can't I just get perl to "automagically" populate the parse tree for me without having to specify a class of actions?
Update: possible solution
Suppose we just want to parse:
my $desc = q:to"FIN";
record person
name string;
age int;
end-record
FIN
and report on the field names and types that we find. I'm going to make a slight simplification to the grammar I wrote above:
grammar rec {
token TOP { <ws>* 'record' \s+ <rec-name> <field-descriptor>+ <ws> 'end-record' <ws> }
token rec-name { \S+ }
token field-descriptor { <ws>* <field-name> <ws>+ <field-type> <ws>* ';' }
token field-name { \S+ }
token field-type { <[a..z]>+ }
token ws { <[\r\n\t\ ]> }
}
Let's eschew actions completely, and just parse it into a tree:
my $r1 = rec.parse($desc);
Let's now inspect our handiwork, and print out the name and type for each field that we have parsed:
for $r1<field-descriptor> -> $fd { say "Name: $fd<field-name>, Type: $fd<field-type>"; }
Our output is as we expect:
Name: name, Type: string
Name: age, Type: int
I know you're now all set but here's an answer to wrap things up for others reading things later.
How do I just create a parse tree with perl6 grammar?
It's as simple as it can get: just use the return value from calling one of the built in parsing routines.
(Provided parsing is successful parse and cousins return a parse tree.)
The output from the code ... looks fairly good. perl6 seems to be decoding the fact that field-descriptors is composed of multiple field-descriptor, but it doesn't actually seem to put them into a list. I can do say $fds;, but I can't do say $fds[0];. Why does the former "work", but the latter doesn't?
See my answer to the SO question "How do I access the captures within a match?".
Would I be better of using rules instead of tokens?
The only difference between a token and a rule is the default for interpreting bare whitespace that you include within the token/rule.
(Bare whitespace within a token is completely ignored. Bare whitespace within a rule denotes "there can be whitespace at this point in the input".)
Do I really need an actions class[?]
No.
Only bother with an actions class if you want to systematically post process the parse tree.
can't I just get perl to "automagically" populate the parse tree for me without having to specify a class of actions?
Yes. Any time you call parse and the parse is successful its return value is a parse tree.
Update: possible solution
Let's eschew actions completely, and just parse it into a tree:
Right. If all you want is the parse tree then you don't need an actions class and you don't need to call make or made.
Conversely, if you want another tree, such as an Abstract Syntax Tree, then you will probably find it convenient to use the built in make and made routines. And if you use make and made you may well find it appropriate to use them in conjunction with a separate actions class rather than just embedding them directly in the grammar's rules/tokens/regexes.

Grails: How to fetch a single item via named queries and additional criteria closure

I am using Grails 2.4.3 and having trouble with named queries.
For example I have this
class Product {
Customer customer
...
static namedQueries = {
byCustomer { Customer c ->
eq('customer', c)
}
}
...
}
Now I can do
Product.byCustomer(customer).list()
I event can do
Product.byCustomer(customer).list(pagination + sorting ) {
...
gt('price', 23.5)
}
If I want a single object from gorm with criterias on it, I usually do
Product.createCriteria().get {
....
eq('name', 'foo')
}
This will return the first matching Product with name == 'foo'
Now, what I want to do is this:
Product.byCustomer(customer).get {
...
eq('type', 'bar')
}
This gives me:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server
version for the right syntax to use near 'from product this_)' at line 1. Stacktrace follows:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for the right syntax to use near
'from product this_)' at line 1
I also tried this:
Product.byCustomer(customer) {
...
eq('type', 'bar')
}.get()
which does also not work, since byCustomer(...) returns a collection.
What do I miss here ? I am really wondering cause all other methods seem to work, except .get() :
Product.byCustomer(customer).count {
...
eq('type', 'bar')
}
(this is working)
I really appreciate any help. Thanks!
UPDATE:
As pointed out there are several options are given if you just want to query a fixed set of properties:
With where clause:
Product.byCustomer(customer).findWhere([type: 'bar'])
With another named query for "type"
Product.byCustomer(customer).byType('bar').get()
Problem: I have a dynamic set of criterias I want to add - and cannot create a named queries for all properties in my domain class.
UPDATE 2:
Example how I want to dynamically build by criteria, based on conditions:
Product p = Product.byCustomer(customer).get() {
if (condition) {
eq('a', params.int('bar'))
gt('b', params.int('foo'))
items {
eq('c', 'baz')
}
} else {
...
}
}
ANSWER
I think I found the way this will work for me. As I use Grails > 2.0 I can use
where-queries which will return DetachedCriteria
DetachedCriteria has the missing get() method and I even can mix findWhere - like syntax with builder syntax - check this out:
Product.where { foo == '5' && bar > 8 }.get()
Or
Product.where { foo == '5' && bar > 8 }.build {
items {
eq('baz', 5)
}
}.get()
In both closures (where + build) I can dynamically add conditions.
Now the final part - reuse the namedQueries which already exists in the above Query
Product.where { foo == '5' && bar > 8 }.build {
items {
eq('baz', 5)
}
Product.byCustomer(customer)
}.get()
Sweet! Unfortunately I cannot answer my own question yet :)
UPDATE
The last part is NOT working. How can I mix DetachedCriteria and named queries ?
Since the result of a named query with a closure argument is a java.util.ArrayList you should be able to do
Product.byCustomer(customer){
...
eq('type', 'bar')
}.getAt(0)
If the result is an empty list it will return null, otherwise it will return the first entry (in your case the only one). Tried with Grails 2.4.3.

how to pass a list to the query in Groovy SQL?

I've a scenario to pass a List of char values to the query in Grails.
When I pass the List this is what happening
def accounts = ['A', 'B']
AND acct.account_status_cd in '${accounts}
the query looks like "AND acct.account_status_cd in '[A,B]'"
but it should be "AND acct.account_status_cd in ('A','B')"
how to achieve this?
Resolved it by Passing as a String...
String s = keys.collect { "'$it'" }.join( ',' )
It gives me S = 'A','B','C'
A solution could be a NamedQuery inside your domain class, something like this:
class Account {
// code omitted
static namedQueries = {
accountsInList { accountList ->
'in'("account_status_cd", accountList)
}
}
Then you can use this namedQuery like:
Account.accountsInList(['A', 'B']).list()
Ofcourse you can also use a withCriteria.
See the docs for more info:
http://grails.org/doc/2.2.x/ref/Domain%20Classes/createCriteria.html

Resources