How to use generated methods within second generator

Hi, 

this time I have a tricky question. The scenario is the following. I have a language LangA that has a lot of concepts and a generator that generates a XML based format. Then I have a second LangB that has only a couple of concepts but they need to have a reference to a root concept of LangA and then generates a lot of java code from these concept definitions. In LangA we define a path to a XSD file that contains type definitions that are necessary in the generation of LangA but more important for the generation of LangB we generate Java classes with JAXB before the code generation step of LangB. 

My question is now how can I define a reference in LangB to a method of the Java Classes generated by JAXB? I know how the method names a created so I can generate the right string (e.g. example.setNumber(42) ) but this string can not be resolved in the generation step later on so I get errors like this:

couldn't resolve reference 'baseMethodDeclaration' from setNumber
-- cannot resolve reference by string: 'setNumber'
-- was input: r:aa428a52-ffdb-4723-a0bf-3a9f74ddda58(LangB.sandbox)/2076007902508729230
-- was template: r:e09fd805-01ff-4ac7-902e-fd3e4dca832d(LangB.generator.template.main@generator)/7040802249638737330

Has anyone done something like this an point me in the right direction?

9 comments

Hi,

 Model elements could reference model elements only, you can't reference plain java code from a model, even if you know name of the generated method. Either java code has to get exposed with java stub model and then references could get resolved, or your method calls have to be 'plain text' references. Look at InternalPartialInstanceMethodCall from jetbrains.mps.baseLanguageInternal to get an idea about the latter approach. Compare it to InstanceMethodCallOperation, which has model reference instanceMethodDeclaration, while InternalPartialInstanceMethodCall keeps only method name as plain string.

0

Hi Artem, 

thanks for the answer. I see the difference. 

One question that came to my mind was If it would be possible to create a temporary java stub model at generation time that includes the java classes generated by JAXB and add this as a dependency to the generator model so I could resolve the references and stick to my existing model 2 model transformations?

Best regards

Phillipp

0

Another idea that came to my mind is if it is possible somehow weave a textGen component into the model to model generation process step so I can keep my current model to model generations and insert the additional needed methods as plain text into the generation process.

0

Though it's possible to create a stub model at generation time, it would be tricky to construct references to it using generator language facilities. The language was designed with a different scenario (where existing input models are traversed and transformed, not when there are in-memory model and one creates references in a thin air). Instead of exploring all peculiarities of generator internals, I'd suggest we try facilities generator provides, perhaps slightly altering the way task is solved. E.g we could try to use EXPORT macro to persist cross-model information if models with LangA and LangB are independent; use BaseLanguage to describe additional input methods (i.e. instead of weaving textgen and using stubs to get these methods into model), or introduce an intermediate language both LangA and LangB would produce that would address reference resolution between artefacts of these. Could you please elaborate and tell me a bit more about relation between LangA and LangB, how abstract these language are, what nodes input model has?

0

Ok I try to explain the scenario in more detail.

So the structure aspect of LangB depends on LangA to contain references to LangA model elements. LangA can be used completely on its own while the usage of LangB implies that at least one root node of LangA is instantiated. The whole model that is create with LangA is generated to XML and also the references to an existing XSD file are generated into that generated XML. 

A root node of LangB now references a root node of LangA and also contains some additional information in order to generate Java code from these models. Therefore the XSD referenced from LangA is used to generate Java class files with JAXB which should then be used from the code generated by the LangB generator aspect. 

I do not understand fully what you mean with "how abstract these languages are". Both languages are very specific to our use case but the Java code generated with them is quite extensive since we are not just generating part of a Java project with it but we generate a whole Java project where just some bits and pieces (read method stubs) need to be implemented after the generation was executed successfully. 

 

0

Let me see if I got it right: there are two models, m1 has rootA from LangA, and is transformed down to XML. There's distinct step that takes these XML and produce JAXB Java code. Then, there's model m2, with rootB (of LangB), which references m1.rootA, and during generation of that model, you need to access some information from the course of m1 generation (i.e. XML-related stuff). Besides, and here's the tricky part, you also need access to Java classes generated from these XMLs, too, to establish references in the m2's Java code. Correct?

 Whether it's single model with rootA and rootB or two distinct models is relevant because model is the smallest chunk generator deals with (from user perspective). If it's single model with two roots, they get transformed simultaneously, i.e. there'd be no step for JAXB generation to jump in - transformation of a model assumes there are only generators that act, aligned to steps according to generation plan, with all roots passing each step of the plan at the same moment. If roots belong to independent models, Make process could be tuned to run two transformation phases, interlaid with JAXB generation phase. Though this is indeed as complicated as it sounds ;)

What if there's BL 'facade' class produced along with XML stuff as part of LangA generation that classes from LangB could reference instead of direct references to JAXB-generated code? If it's not an option, I'm affraid the only feasible solution at the moment is to use InternalXXXCall approach. 

 

0

Yes you almost have it right, the only thing that is different is that the XML output of LangA is not referenced by LangB. LangA has a reference to a XSD file because the information of that file is necessary for the generation of the XML output of LangA. In the intermediate step this XSD file is then generated also to Java classes which are then referenced by LangB. For the generation of LangB the generation to XML of LangA is not necessary but the information contained in the m1 is needed in order to be able to generate m2. 

Since I have two distinct models how can I tune the make process to be rerun as described by you?

0

I finally came up with a solution that works for my scenario without messing with MPS and its generation mechanics. I generate the method calls to the generated methods using the java reflection API. Since I know how the method names are set up. I still have to take care of all the possible runtime exceptions but for me this is the cleanest way of doing this that I could come up with.

Thanks for all the help.

0

Somehow I've missed your previous response. To tune make process, you'd need custom make facet, which is quite complicated effort.

What you did is an alternative way to accomplish what I've referred to as internalXXXCalls. E.g. there InternalPartialInstanceMethodCall in blInternal language, which basically just holds name of an instance method to invoke, but doesn't require to have a model/node for the method.

0

Please sign in to leave a comment.