I have recently started working with XText. So far I have been able to define a simple grammar, complete the JvmModelInferrer and generate the corresponding java classes and .java files.
Is it possible to generate automatically the DSL file (taking into account its grammar) from a set of custom Java classes?
Let me provide a simple example.
I have the following grammar:
MODEL:
entities+=ENTITY*
;
ENTITY:
'entity' name=ValidID 'as'
(elements+=PROPERTY)*
'end'
;
PROPERTY:
(many?='many')? 'property' name=ID 'of' type=JvmTypeReference
;
If I have the following sample.myDsl
entity Book as
property title of String
property numPages of Integer
end
entity Author as
property name of String
property surname of String
end
I get the Book.java and the Author.java files. In my project I have a processor that analyzes java files and creates objects from them, so if I run the processor on the previous Book.java and Author.java I would get two instances of a custom Entity java type. Each Entity instance would have a set of Property instances. So, the Java model is very similar to the xtext grammar.
Is it possible to "feed" these two objects to XText, maybe define an Inferrer to specify the translations, and taking into account the same .xtext grammar file, generate automatically a .myDsl file?
with xtext it is ususally no problem to
if you use xbase and jvmmodelinferrrer building the ast might be a kind of pain if you reference from a model to a inferred jvm element or try to build xbase expressions as ast here is a simple complex example using the domainmodel example
package org.eclipse.xtext.example.domainmodel.tests
import com.google.inject.Injector
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.emf.ecore.resource.ResourceSet
import org.eclipse.xtext.common.types.JvmParameterizedTypeReference
import org.eclipse.xtext.common.types.util.TypeReferences
import org.eclipse.xtext.example.domainmodel.DomainmodelStandaloneSetup
import org.eclipse.xtext.example.domainmodel.domainmodel.DomainmodelFactory
import org.eclipse.xtext.resource.DerivedStateAwareResource
import org.eclipse.xtext.resource.SaveOptions
import org.eclipse.xtext.xbase.jvmmodel.JvmTypeReferenceBuilder
class Main {
var static extension DomainmodelFactory factory = DomainmodelFactory.eINSTANCE
def static void main(String[] args) {
var Injector injector = new DomainmodelStandaloneSetup().createInjectorAndDoEMFRegistration()
val ResourceSet resourceSet = injector.getInstance(ResourceSet)
val Resource r0 = resourceSet.createResource(URI.createURI("base/Base.dmodel"))
val Resource r1 = resourceSet.createResource(URI.createURI("model/Person.dmodel"))
val typeReferenceBuilder = injector.getInstance(JvmTypeReferenceBuilder.Factory).create(resourceSet)
val typeReferences = injector.getInstance(TypeReferences)
val model = createDomainModel
r1.contents += model
val model0 = createDomainModel
r0.contents += model0
// build the ast using xtends with clause
model0 => [
elements += createPackageDeclaration => [
name = "base"
elements += createEntity => [
name = "Base"
features+= createProperty => [
name = "id"
type = typeReferenceBuilder.typeRef("java.lang.String")
println(type)
]
]
]
]
//trigger the inferrer on resource 0
(r0 as DerivedStateAwareResource) => [
fullyInitialized = false
installDerivedState(false)
]
// build the ast of the second resource
model => [
elements += createPackageDeclaration => [
name = "model"
elements += createEntity => [
val base = typeReferences.findDeclaredType("base.Base", resourceSet)
println(base)
superType = typeReferenceBuilder.typeRef(base) as JvmParameterizedTypeReference
println(superType)
name = "Person"
features+= createProperty => [
name = "name"
type = typeReferenceBuilder.typeRef("java.lang.String")
println(type)
]
]
]
]
//save the resources
r0.save(SaveOptions.defaultOptions.toOptionsMap)
r1.save(SaveOptions.defaultOptions.toOptionsMap)
}
}