Import packageDefinition '.' InterfaceDefinition when defining xtext grammar - java

I am trying to create a simple grammar using xText. The grammar should define language for Java Interfaces (only) and currently I am struggling with import declarations. I want to be able to reference other interfaces form other packages that I have defined using their FQNs. Here is how my grammar look like:
DomainModel:
elements=AbstractElement;
AbstractElement:
'package' packageDeclaration=PackageDeclaration
'import'? importDeclarations+=ImportDeclaration*
typeDeclaration=TypeDeclaration;
PackageDeclaration:
name=QualifiedName ';';
ImportDeclaration:
importedNamespace=[ReferncedType|QualifiedName] ('.*')? ';';
ReferncedType:
PackageDeclaration |InterfaceDeclaration; //need to combine both?? separated by '.'
TypeDeclaration:
'interface' interfaceDeclaration=InterfaceDeclaration;
TypeList:
Type ( ',' type+=Type)*;
Type:
typeDefinition=[ReferncedType|ValidID];
InterfaceDeclaration:
name=ValidID ('extends' superType=TypeList)? body=InterfaceBody;
InterfaceBody:
'{' (declarations+=InterfaceBodyDeclaration)+ '}';
InterfaceBodyDeclaration:
interfaceMemberDelcaration+=InterfaceMemberDeclaration ';';
InterfaceMemberDeclaration:
InterfaceMethodDeclaration;
InterfaceMethodDeclaration:
(Type | 'void') name+=ValidID '(' (formalParameters+=FormalParameters)* ')' ('throws'
....)?;
I have defined both files:
package org.first.sample;
interface Demo {
void getA();
}
....
package org.second.sample;
import org.first.sample.Demo; // this line says that the reference to org.first.sample.Demo is invalid, but I am able to reference org.first.sample
interface AnotherDemo {
Demo getDemo();
}
Do you have any ideas?

As I read the grammar:
ImportDeclaration:
importedNamespace=[ReferncedType|QualifiedName] ('.*')? ';';
ReferncedType:
PackageDeclaration |InterfaceDeclaration; //need to combine both?? separated by '.'
PackageDeclaration:
name=QualifiedName ';';
So import can be followed by a (PackageDeclaration=QualifiedName followed by a ; and then, back to rule ImportDeclaration, another ; must follow.
Also, I don't understand why ReferncedType can also expand to an InterfaceDeclaration, which is the entire thing?
Later
So, perhaps the "import" should be defined as
AbstractElement:
'package' packageDeclaration=PackageDeclaration
importDeclarations+=ImportDeclaration*
...
ImportDeclaration
'import' importedNamespace=QualifiedName ('.*')? ';';
It doesn't permit static imports, and something must be done to keep track of .* if it occurs.

You can bind a custom QualifiedNameProvider to override name exported by your interfaces.
Something like this should make the import reference ok : (import org.first.sample.Demo;)
public class CustomQualifiedNameProvider extends DefaultDeclarativeQualifiedNameProvider {
#Override
public QualifiedName getFullyQualifiedName(EObject obj) {
if (obj instanceof InterfaceDeclaration && obj.eContainer().eContainer() instanceof AbstractElement) {
QualifiedName packageQualifiedName = getFullyQualifiedName(((AbstractElement)obj.eContainer().eContainer()).getPackageDeclaration());
return packageQualifiedName.append(((InterfaceDeclaration) obj).getName());
}
return super.getFullyQualifiedName(obj);
}
}
Also, you can press Ctrl + Shift + F3 to see what name have your exported objects.

Actually #laune is right. Xtext supports this out of the box. As long as the referred types in the model have feature called 'name', the fully qualified name of the type is built out-of-the box. What I noticed that is wrong in my Xtext grammar definition is that Package should contain Interface, so that when a fully qualified name is formed xtext is constucting it by combining the 'name' of the Interface with the 'name' of the package (or its parent).
#Fabien your answer is correct in case the xtext grammar rules doesn't contain 'name' features. It is a custom way of building fqns if for example we are using this:
Package:
'package' name=ID ';' imports=Import ';' interface=Interface ';'
;
Interface:
qualifier=Qualifier !id=ID (instead of name=ID)
;
Then we should construct explicitly the fqn because the built-in support looks for 'name' features only.
So in my case the correct way to use this is:
Package:
'package' name=ID; imports=Import typeDefinition=TypeDefinition;
Import:
'import' importedNamespace=[TypeDefinition|QualifiedName] ';'
;
TypeDefinition:
InterfaceDefinition | EnumDefinition ...
;
InterfaceDefinition:
qualifier=Qualifier !name=ID
;

Related

How to reference attribute from .bnf parser in JFlex?

I'm using a .bnf parser to detect specific expressions and I'm using JFlex to detect the different sections of these expressions. My issue is, some of these expressions may contain nested expressions and I dont know how to handle that.
I've tried to include the .bnf parser in my JFlex by using %include, then referencing the expression in the relative macro using PARAMETERS = ("'"[:jletter:] [:jletterdigit:]*"'") | expression. This fails as JFlex reports the .bnf to be malformed.
Snippet of JFlex:
%{
public Lexer() {
this((java.io.Reader)null);
}
%}
%public
%class Lexer
%implements FlexLexer
%function advance
%type IElementType
%include filename.bnf
%unicode
PARAMETERS= ("'"[:jletter:] [:jletterdigit:]*"'") | <a new expression element>
%%
<YYINITIAL> {PARAMETERS} {return BAD_CHARACTER;} some random return
Snippet of .bnf parser:
{
//list of classes used.
}
expression ::= (<expression definition>)
Any input would be greatly appreciated. Thanks.
I've found the solution to my issue. In further depth, the problem was in both my grammar file and my flex file. To solve the issue, I recursively called the expression in the grammar file like so:
expression = (start value expression? end)
With the JFlex, I declared numerous states until I found a way to chain together and endless amount of expressions. Looks a little like this:
%state = WAITING_EXPRESSION
<WAITING_NEXT> "<something which indicates start of nested expression>" { yybegin(WAITING_EXPRESSION); return EXPRESSION_START; }

line breaks after Java annotations in Scala code

I have a code that compiles successfully:
import javax.ws.rs.Path
trait DescriptionHandler extends ServiceAwareHandler {
#Path("/descriptions")
def getDescriptionsRoute: Route = ...
}
and it would not compile if I add a line break after Path annotation like this:
import javax.ws.rs.Path
trait DescriptionHandler extends ServiceAwareHandler {
#Path("/descriptions")
def getDescriptionsRoute: Route = ...
}
In IntelliJ IDEA it look like javax.ws.rs.Path is absent in class path.
Compiler telling me this:
Error:(19, 1) expected start of definition
def getDescriptionsRoute: Route =
What's the problem with line breaks between Java annotations and Scala methods / fields? I tried to google the issue but didn't found anything useful.
In Scala Spec/Lexical syntax/1.2 Newline characters there is an explicit statement about this case:
A single new line token is accepted
...
after an annotation.
And when there is an empty line:
if two tokens are separated by at least one completely blank line (i.e a line which contains no printable characters), then two nl tokens are inserted.
Thus blank lines are not accepted between annotation and definition.

Xtext - No viable alternative at input

i'm trying to create a grammar that join togheter a script language with the possibility to create method.
Grammar
grammar org.example.domainmodel.Domainmodel with org.eclipse.xtext.xbase.Xbase
generate domainmodel "http://www.example.org/domainmodel/Domainmodel"
import "http://www.eclipse.org/xtext/xbase/Xbase" as xbase
Model:
imports = XImportSection
methods += XMethodDeclaration*
body = XBlockScriptLanguage;
XMethodDeclaration:
"def" type=JvmTypeReference name=ValidID
'('(params+=FullJvmFormalParameter (',' params+=FullJvmFormalParameter)*)? ')'
body=XBlockExpression
;
XBlockScriptLanguage returns xbase::XExpression:
{xbase::XBlockExpression}
(expressions+=XExpressionOrVarDeclaration ';'?)*
;
At the moment i create the following JvmModelInferr, for defining the main method for scripting language.
JvmModelInferr
def dispatch void infer(Model model, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(
model.toClass("myclass")
).initializeLater [
members += model.toMethod("main", model.newTypeRef(Void::TYPE)) [
parameters += model.toParameter("args", model.newTypeRef(typeof(String)).addArrayTypeDimension)
setStatic(true)
body = model.body
]
]
}
When i tryed to use my grammar, i obtain the following error after that i wrote my method:
no viable alternative at input 'def'
The method mymethod() is undefined
The problem is related only with method declaration, without it myclass.java is created.
Moreover i obtain the "Warning 200" for a not clear grammar, why?
There are two fixes that appear necessary:
The imports section is not marked as optional. If it was intended to be optional, it should be declared as imports ?= XImportSection. Or, add necessary import statements to your JvmModelInferr example.
The dispatch keyword isn't defined in your grammar. As defined, a method should consist of def, followed by a Java type (the return type), and then the method's name (then the body, etc.). You could add `(dispatch ?= 'dispatch') if you're targeting Xtend and intend to support its multiple dispatch feature (or your own version of it).
HTH

TestRig in ANTLRworks: how to use own classes?

I'm trying to build a MT940 parser using antlr4. The grammar is simple but works for most cases.
Now I want to return my own classes. This works:
file returns [String myString]
:
Header940? record+ EOF
;
I think this is becasue String is in the default java packages.
I want this:
file returns [List<MT940Record> records]
:
Header940? record+ EOF
;
The TestRig complains (logically):
/tmp/TestRigTask-1392235543340/MT940_5aParser.java:50: error: cannot find symbol
public List<MT940Record> records;
^
symbol: class MT940Record
location: class FileContext
How can I set the CLASSPATH / lib directory in the TestRig in ANLTRWorks?
In ANTLRWorks, you can't. You can add an issue for this on the issue tracker:
https://github.com/sharwell/antlrworks2/issues
Note that ANTLR 4 was designed so you no longer need to use user-defined arguments and/or return values in your grammar. Instead of returning a List<MT940Record> like you described above, you should use a listener or visitor after the parse is complete to compute the necessary result.

Understanding trees in ANTLR

I'm trying to use Antlr for some text IDE-like functions -- specifically parsing a file to identify the points for code folding, and for applying syntax highlighting.
First question - is Antlr suitable for this requirement, or is it overkill? This could be achieved using regex and/or a hand-rolled parser ... but it seems that Antlr is out there to do this work for me.
I've had a look through the ... and the excellent tutorial resource here.
I've managed to get a Java grammar built (using the standard grammar), and get everything parsed neatly into a tree. However, I'd have expected to see elements nested within the tree. In actual fact, everything is a child of the very top element.
Eg. Given:
package com.example
public class Foo {
String myString = "Hello World"
// etc
}
I'd have expected the tree node for Foo to be a child of the node for the package declaration. Likewise, myString would be a child of Foo.
Instead, I'm finding that Foo and myString (and everything else for that matter) are all children of package.
Here's the relevant excerpt doing the parsing:
public void init() throws Exception {
CharStream c = new ANTLRFileStream(
"src/com/inversion/parser/antlr/Test.code");
Lexer lexer = new JavaLexer(c);
CommonTokenStream tokens = new CommonTokenStream(lexer);
JavaParser parser = new JavaParser(tokens);
parser.setTreeAdaptor(adaptor);
compilationUnit_return result = parser.compilationUnit();
}
static final TreeAdaptor adaptor = new CommonTreeAdaptor() {
public Object create(Token payload) {
if (payload != null)
{
System.out.println("Create " + JavaParser.tokenNames[payload.getType()] + ": L" + payload.getLine() + ":C" + payload.getCharPositionInLine() + " " + payload.getText());
}
return new CommonTree(payload);
}
};
Examining result.getTree() returns a CommonTree instance, whose children are the result of the parsing.
Expected value (perhaps incorrectly)
package com.example (4 tokens)
|
+-- public class Foo (3 tokens)
|
+--- String myString = "Hello World" (4 tokens)
+--- Comment "// etc"
(or something similar)
Actual value (All values are children of the root node of result.getTree() )
package
com
.
example
public
class
Foo
String
myString
=
"Hello World"
Is my understanding of how this should be working correct?
I'm a complete noob at Antlr so far, and I'm finding the learning curve quite steep.
The Java-6 grammar at the top of the file sharing section on antlr.org does not include tree building. You'll need to do two things. First, tell ANTLR you want to build an AST:
options {
output=AST;
}
Second, you need to tell it what the tree should look like by either using the tree operators or by using the rewrite rules. See the documentation on tree construction. I usually end up doing a combination of both.
To build tree, you should set output=AST. (Abstract syntax tree)
As far as I know, in an ANTLR only 1 token can be the root of a tree, so you can't get exactly what you're looking for, but you can get close.
Check out:
http://www.antlr.org/wiki/display/ANTLR3/Tree+construction

Categories