I'm developing a DSL, and I'm using Xtext's importURI attibute to deal with imports. It is working fine in the editor, but I don't know how to query the root element of the resource from the importURIs - which are just strings (later, in Acceleo). What would be the best way to do that?
P.S. My DSL allows only explicit imports. Also I have 2 meta-models : First one's root element is Alg, and the second one imports Alg(s) (root element - Root).
Right now, I have a Service that "goes" through all elements and return the root element of the imported resources. I think there is no need to go through the whole tree just to find something that could be deduced from import statements.
So, what would be the List<Alg> getAlgs(Root root) java method to retrieve all Alg roots?
Grammar:
Root returns Root:
{Root} (name = QualifiedName ":")?
(importStatement += ImportStatement)*
[...];
ImportStatement:
'import' importURI=STRING;
[...]
Acceleo:
[query public getAlgRoot(arg0 : Root) : Sequence(Alg)
= invoke('org.example.tojava.services.AlgpRootService', 'getAlgs(org.example.mydsl.model.Root)', Sequence{arg0})
/]
Usually the STRING in importURI should be a URI that points to the resource you wish to import, which makes its elements accessible for cross-references in your original grammar. So I would say you are simply missing the cross-reference to Alg objects.
Related
we are trying to add parameters to a transformation at the runtime. The only possible way to do so, is to set every single parameter and not a node. We don't know yet how to create a node for the setParameter.
Current setParameter:
QName TEST XdmAtomicValue 24
Expected setParameter:
<TempNode> <local>Value1</local> </TempNode>
We searched and tried to create a XdmNode and XdmItem.
If you want to create an XdmNode by parsing XML, the best way to do it is:
DocumentBuilder db = processor.newDocumentBuilder();
XdmNode node = db.build(new StreamSource(
new StringReader("<doc><elem/></doc>")));
You could also pass a string containing lexical XML as the parameter value, and then convert it to a tree by calling the XPath parse-xml() function.
If you want to construct the XdmNode programmatically, there are a number of options:
DocumentBuilder.newBuildingStreamWriter() gives you an instance of BuildingStreamWriter which extends XmlStreamWriter, and you can create the document by writing events to it using methods such as writeStartElement, writeCharacters, writeEndElement; at the end call getDocumentNode() on the BuildingStreamWriter, which gives you an XdmNode. This has the advantage that XmlStreamWriter is a standard API, though it's not actually a very nice one, because the documentation isn't very good and as a result implementations vary in their behaviour.
Another event-based API is Saxon's Push class; this differs from most push-based event APIs in that rather than having a flat sequence of methods like:
builder.startElement('x');
builder.characters('abc');
builder.endElement();
you have a nested sequence:
Element x = Document.elem('x');
x.text('abc');
x.close();
As mentioned by Martin, there is the "sapling" API: Saplings.doc().withChild(elem(...).withChild(elem(...)) etc. This API is rather radically different from anything you might be familiar with (though it's influenced by the LINQ API for tree construction on .NET) but once you've got used to it, it reads very well. The Sapling API constructs a very light-weight tree in memory (hance the name), and converts it to a fully-fledged XDM tree with a final call of SaplingDocument.toXdmNode().
If you're familiar with DOM, JDOM2, or XOM, you can construct a tree using any of those libraries and then convert it for use by Saxon. That's a bit convoluted and only really intended for applications that are already using a third-party tree model heavily (or for users who love these APIs and prefer them to anything else).
In the Saxon Java s9api, you can construct temporary trees as SaplingNode/SaplingElement/SaplingDocument, see https://www.saxonica.com/html/documentation12/javadoc/net/sf/saxon/sapling/SaplingDocument.html and https://www.saxonica.com/html/documentation12/javadoc/net/sf/saxon/sapling/SaplingElement.html.
To give you a simple example constructing from a Map, as you seem to want to do:
Processor processor = new Processor();
Map<String, String> xsltParameters = new HashMap<>();
xsltParameters.put("foo", "value 1");
xsltParameters.put("bar", "value 2");
SaplingElement saplingElement = new SaplingElement("Test");
for (Map.Entry<String, String> param : xsltParameters.entrySet())
{
saplingElement = saplingElement.withChild(new SaplingElement(param.getKey()).withText(param.getValue()));
}
XdmNode paramNode = saplingElement.toXdmNode(processor);
System.out.println(paramNode);
outputs e.g. <Test><bar>value 2</bar><foo>value 1</foo></Test>.
So the key is to understand that withChild() returns a new SaplingElement.
The code can be compacted using streams e.g.
XdmNode paramNode2 = Saplings.elem("root").withChild(
xsltParameters
.entrySet()
.stream()
.map(p -> Saplings.elem(p.getKey()).withText(p.getValue()))
.collect(Collectors.toList())
.toArray(SaplingElement[]::new))
.toXdmNode(processor);
System.out.println(paramNode2);
There seems to be no examples online, according to the documentation Path, ParentMap's constructor accepts "Stmt *ASTRoot", which may means that later the ParentMap instance will find parents under the AST subtree under "ASTRoot". But how to get the root node of a translation unit? I tried
virtual bool VisitTranslationUnitDecl(TranslationUnitDecl *decl) {
//decl->dump();
Stmt *stmt = decl->getBody();
mParentMap = new ParentMap(stmt);
return true;
}
The goal is to create a ParentMap around the root nood then use it in other Visit*** callbacks during the scan process. But decl->getBody() is null. decl->dump() will print everything, and even scan the AST for the second time decl->getBody() is still null.
How to get the root Stmt of an AST? What is the right/better way to use ParentMap?
ParentMap is not really intended to be used on its own. You can use ASTContext::getParents, which constructs and maintains ParentMap.
Why directory comparison does not work the expected way in Dart?
import 'dart:io';
void main() {
Directory d = Directory('/kek');
Directory e = Directory('/kek');
print(d==e); // false
print(d.hashCode); // 123456
print(e.hashCode); // 654321
}
As I read the documentation for the Directory object, the hashCode and operator== methods are simply inherited from Object, and thus have no special implementation that would cause two different Directory objects to compare equal if they point to the same place.
This would be difficult to implement. Should the hashCode canonicalize relative paths and paths containing "." and ".."? Should it follow symlinks? What about files with multiple hard links?
In MiniGUi, I can see db.index. How do I set it to tree.spatial.rstarvariants.rstar.RStartTreeFactory via Java code?
I have implemented:
params.addParameter(AbstractDatabase.Parameterizer.INDEX_ID,tree.spatial.rstarvariants.rstar.RStarTreeFactory);
For the second parameter of addParameter() function tree.spatial...RStarTreeFactory class not found
// Setup parameters:
ListParameterization params = new ListParameterization();
params.addParameter(
FileBasedDatabaseConnection.Parameterizer.INPUT_ID,
fileLocation);
params.addParameter(AbstractDatabase.Parameterizer.INDEX_ID,
RStarTreeFactory.class);
I am getting NullPointerException. Did I use RStarTreeFactory.class correctly?
The ELKI command line (and MiniGui; which is a command line builder) allow to specify shorthand class names, leaving out the package prefix of the implemented interface.
The full command line documentation yields:
-db.index <object_1|class_1,...,object_n|class_n>
Database indexes to add.
Implementing de.lmu.ifi.dbs.elki.index.IndexFactory
Known classes (default package de.lmu.ifi.dbs.elki.index.):
-> tree.spatial.rstarvariants.rstar.RStarTreeFactory
-> ...
I.e. for this parameter, the class prefix de.lmu.ifi.dbs.elki.index. may be omitted.
The full class name thus is:
de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.rstar.RStarTreeFactory
or you just type RStarTreeFactory, and let eclipse auto-repair the import:
params.addParameter(AbstractDatabase.Parameterizer.INDEX_ID,
RStarTreeFactory.class);
// Bulk loading static data yields much better trees and is much faster, too.
params.addParameter(RStarTreeFactory.Parameterizer.BULK_SPLIT_ID,
SortTileRecursiveBulkSplit.class);
// Page size should fit your dimensionality.
// For 2-dimensional data, use page sizes less than 1000.
// Rule of thumb: 15...20 * (dim * 8 + 4) is usually reasonable
// (for in-memory bulk-loaded trees)
params.addParameter(AbstractPageFileFactory.Parameterizer.PAGE_SIZE_ID, 300);
See also: Geo Indexing example in the tutorial folder.
For our master project at university we created multiple DSLs using Xtext. One of the DSLs is a model entity DSL which allows the user to create a class with properties and methods.
We reuse Xbase because, of course, we want the methods to have a real programming language without reinventing the wheel:
grammar … with org.eclipse.xtext.xbase.Xbase
generate …
EntityModel:
'package' importedNamespace=QualifiedName
…
implementation=Entity;
Entity:
'entity' name=ValidID '{'
features+=Feature*
'}';
Feature:
LocalVariable | …;
LocalVariable:
'var' (isStatic?='static')? name=ValidID ':' type=JvmTypeReference;
For some reason, even though the type of the LocalVariable is set to JvmTypeReference, when using String (in an actual implementation), it will always show the error
Xtext: Couldn't resolve reference to JvmType 'String'
package com.example
Entity foo {
var bar: String
}
We already tried using a ImportedNamespaceAwareLocalScopeProvider which in getImportedNamespaceResolvers adds java.lang.* like that:
List<ImportNormalizer> implicitImports = super.getImportedNamespaceResolvers(context, ignoreCase);
List<ImportNormalizer> javaLangImports = singletonList(new ImportNormalizer(QualifiedName.create("java", "lang"), true, ignoreCase));
implicitImports.addAll(javaLangImports);
return implicitImports;
Even thought that method is called a lot of times, the imports still don't work. When inspecting the EObject context parameter, it sometimes returns java.lang.String (which I guess is for the JvmTypeReference but it still displays an error.
In the RuntimeModule the new scope provider is configured like that:
public void configureIScopeProviderDelegate(com.google.inject.Binder binder) {
binder.bind(org.eclipse.xtext.scoping.IScopeProvider.class).annotatedWith(com.google.inject.name.Names.named(org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider.NAMED_DELEGATE)).to(MasterDSLImportedNamespaceAwareLocalScopeProvider.class);
}
In the Workflow we configured
fragment = scoping.ImportNamespacesScopingFragment {}
fragment = exporting.QualifiedNamesFragment {}
fragment = builder.BuilderIntegrationFragment {}
The rest of the project is quite complex already (4 Xtext DSLs in one project and multiple generators). But except for completely different DSLs, they use almost the same workflow and RuntimeModule configuration. Another DSL also uses JvmTypeReference and also doesn't find e.g. boolean or anything else.
The question of course is: are we doing something wrong or is there something else we have to do. It used to work when we had a significantly smaller project but after some major changes suddenly this stopped working.