Xtext validator - check all elements X for element Y validation - dsl

I'm here trying to find out if anyone know how can I, in my grammar, make a validator that checks if my step only uses ingredients I have declared before hand in the 'ingredients+=Ingredient+'
I've tried many things but no success, I don't know how can I get all the Ingredients that are declared inside my validator function.
Ty all for your time.
Here is the relevant part of my grammar.
Model:
recipe+=Recipe*;
...
Ingredient:
'ingredient' (
(liquid_name=LIQUID_INGREDIENTS_NAME liquid_measure=LIQUID_TYPES_MEASURE)
|
(solid_Name=SOLID_INGREDIENTS_NAME solid_measure=SOLID_TYPES_MEASURE)
)
quantity=INT;
Step:
'['
action=ACTION_TYPES
('ingredient' ((ingredient_StepLiquid=LIQUID_INGREDIENTS_NAME)|(ingredient_StepSolid=SOLID_INGREDIENTS_NAME)) | 'place' place=TM_PLACES | 'utensil' utensil=TM_UTENSILS)
('time' minutes=INT ':' seconds=INT ',')?
('speed' velocidade=SPEED_TYPES ',')?
('temperature' temp=TM_TEMPS 'ºC')?
']';
Recipe:
'recipe' recipeName=STRING '{'
ingredients+=Ingredient+
steps+=Step+
'}';

Just like #Christian Deitrich said
I can use either eContainer, and get my recipe with a cast from my step or via my grammar with the help from cross references.

Related

Antlr no viable alternative at input when the keyword is POINT

import org.antlr.v4.runtime.tree.ParseTree;
import org.apache.shardingsphere.sql.parser.core.parser.SQLParserExecutor;
import org.junit.Test;
import javax.xml.bind.SchemaOutputResolver;
public class T1 {
#Test
public void t1() {
ParseTree parseTree = new SQLParserExecutor("MySQL", "insert into T_NAME (POINT) values (?)").execute().getRootNode();
}
}
This code will report the following error:
line 1:20 no viable alternative at input '(POINT'
When I use other column names, it’s all right, but POINT doesn’t work. Why?
Java project, pom.xml:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>4.1.1</version>
</dependency>
I suspect that all (MySQL), or more, keywords would trigger this error (POLYGON probably also produces this error). The grammar probably is trying to match an identifier, but since the input POINTS is already matched as a keyword, it fails to match it properly.
Something like this:
insert_stat
: INSERT INTO? table_name '(' column_names ')' ...
;
column_names
: IDENTIFIER ( ',' IDENTIFIER )*
;
Looking at the Github issue, one of the maintainers indicated that the 5.0.0-alpha properly handles this, meaning they probably did something like this to fix it:
insert_stat
: INSERT INTO? table_name '(' column_names ')' ...
;
column_names
: identifier ( ',' identifier )*
;
identifier
: IDENTIFIER
| POINT
| POLYGON
| ...
;
I.e.: they extended the set of valid identifiers inside the parser.
Thanks for #Bart's comment Here. This bug has been fixed from 5.0.0-alpha.
BTW, ShardingSphere supports many mainstream RDBMS, like MySQL, PostgreSQL, SQLServer and Oracle. Therefore you will see a great many g4 files in this repo. Ideally, these definitions in Antlr g4 file are expected to be aligned with the corresponding official SQL docs. So if there is any mismatch, please report that at ISSUES. Thanks a lot.

Antl4 no rule index for labelled rules

For the grammar snippet from Java.g4,
statement
: block # blockStmt
| 'if' parExpression statement ('else' statement)? # ifStmt
| 'for' '(' forControl ')' statement # forStmt
| 'while' parExpression statement # whileStmt
;
All the alternatives are labelled.
I can get all StatementContext objects using this method
Trees.getAllRuleNodes(root,JavaParser.Rule_statement);
But if I am only interested in getting the IfStmtContext objects, how can I use the above method without using something like this
for(ParseTree tree : statementContextList)
{
if(tree instanceof IfStmtContext)
{
//add to a list
}
The generated JavaParser doesnt create rule indexes for labelled rules.
Do I have to customize the grammar in some way to make them indexed?
Or there is another ways do this?
My code should be fast and I need to remove as much as iterations and conditions as possible. Need to get rid of the 'instanceof' checks as well as possible

An obscure corner of the Haskell Report

Section 5.2 of the Haskell 2010 Report deals with module export lists. At one point, it says:
Entities in an export list may be named as follows:
A value, field name, or class method, whether declared in the module body or imported, may be named by giving the name of the value as a qvarid, which must be in scope. Operators should be enclosed in parentheses to turn them into qvarids.
...
But, uh... am I missing something? Because according to the Syntax Reference in Chapter 10:
qvarid → [ monid . ] varid
varid → ( small { small | large | digit | ' })
So in which universe does putting an operator in brackets turn it into a qvarid? It looks to me like an operator is clearly a varsym (or maybe qvarsym).
Does anybody know what's going on here? I mean, clearly Haskell definitely supports writing operators in an export list, but the syntax description in the Report doesn't appear to make sense...
Wait, hold up... According to the Control-Free Syntax given in section 10.5:
export → qvar | qtycon ... | qtycls ... | module monid
...
var → varid | ( varsym )
qvar → qvarid | ( qvarsym )
So it seems that it's not a qvarid, it's supposed to be a qvar. So it's just a typo, I guess? Is there a process for having such things fixed in the official report?

how to handle conditionally existing components in action code?

This is another problem I am facing while migrating from antlr3 to antlr4. This problem is with the java action code for handling conditional components of rules. One example is shown below.
The following grammar+code worked in antlr3. Here, if the unary operator is not present, then a value of '0' is returned, and the java code checks for this value and takes appropriate action.
exprUnary returns [Expr e]
: (unaryOp)? e1=exprAtom
{if($unaryOp.i==0) $e = $e1.e;
else $e = new ExprUnary($unaryOp.i, $e1.e);
}
;
unaryOp returns [int i]
: '-' {$i = 1;}
| '~' {$i = 2;}
;
In antlr4, this code results in a null pointer exception during a run, because 'unaryOp' is 'null' if it is not present. But if I change the code like below, then antlr generation itself reports an error:
if($unaryOp==null) ...
java org.antlr.v4.Tool try.g4
error(67): missing attribute access on rule reference 'unaryOp' in '$unaryOp'
How should the action be coded for antlr4?
Another example of this situation is in if-then-[else] - here $s2 is null in antlr4:
ifStmt returns [Stmt s]
: 'if' '(' e=cond ')' s1=stmt ('else' s2=stmt)?
{$s = new StmtIf($e.e, $s1.s, $s2.s);}
;
NOTE: question 16392152 provides a solution to this question with listeners, but I am not using listeners, my requirement is for this to be handled in the action code.
There are at least two potential ways to correct this:
The "ANTLR 4" way to do it is to create a listener or visitor instead of placing the Java code inside of actions embedded in the grammar itself. This is the only way I would even consider solving the problem in my own grammars.
If you still use an embedded action, the most efficient way to check if the item exists or not is to access the ctx property, e.g. $unaryOp.ctx. This property resolves to the UnaryOpContext you were assuming would be accessible by $unaryOp by itself.
ANTLR expects you access an attribute. Try its text attribute instead: $unaryOp.text==null

Xtext cross referencing and scoping

I have some problems with xtext cross referencing
Here is a very simple grammer:
grammar org.xtext.example.mydsl1.Test with org.eclipse.xtext.common.Terminals
generate test "http://www.xtext.org/example/mydsl1/Test"
Model: block=Block? cs+=Company* ;
Block: '{' g=[Employee] '}';
Company: 'Company' name=ID
'{' es+= Employee* '}';
Employee: 'Employee' name=ID ';' ;
and it is my dsl :
{ Pooyan }
Company Sony{
Employee Pooyan;
Employee John;
}
It always shown that "Couldn't resolve reference to Employee 'Pooyan'."
Could anyone please help me?
I have no idea...
The fully qualified name of Pooyan is Sony.Pooyan. Since the cross reference 'g' in your block is defined in another contain, you have to do a minor customizing to put it onto the scope.
If your language always uses a flat namespace, you could enable the SimpleNamesFragment in the language generator and remove the QualifiedNamesFragment. This should do the trick.
Alternatively, you could customize the scoping for the concrete reference 'g' in your scope provider.
Adding to Sebastians' answer to make it more precise: you need to change "fragment = exporting.QualifiedNamesFragment auto-inject {}" to "fragment = exporting.SimpleNamesFragment" in the corresponding .mwe2 file of your xtext project.
Hope this helps.

Resources