How to generate variable declaration with references being preserved
Hi!
In my language I have a complex statement that contains a complex expression and optional variable declaration.
Structurally variable declaration is a child of my statement, cuz I wanted it to look not like a classical variable declaration,but like a part of the complex statement (that may be turned on or off).
So when my statement `Execute Command` is called - there's a `Save Result` intention,
that initializes internal variable declaration.
I got my typesystem and scopes perfectly implemented, so functionally it works fine.
Rest of the method body sees these declarations as final local variables and may reference them.
But! When generation is started I need to compile my statement in either the `ExpressionStatement`, or the `LocalVariableDeclaration`,
based on the inner variable being used or not.
The problem is that when I generate new `LocalVariableDeclaration` - all variable references that referenced declaration from my command get broken, and they cannot resolve new declaration.
```
Failed to replace dynamic reference 'variableDeclaration' with static counterpart: no target; resolveInfo=myVar. Dynamic reference is left intact.
Could not resolve reference 'variableDeclaration' from myVar.
a910439a-d168-4aa5-9421-37d06025466a/r:55604285-5df7-43b6-9706-7cfc46d5e886(storyteller.sandbox@transient13/storyteller.qqq@0)/7104292957078701623
-- cannot resolve reference by string: 'myVar'
-- was input: a910439a-d168-4aa5-9421-37d06025466a/r:55604285-5df7-43b6-9706-7cfc46d5e886(storyteller.sandbox@transient13/storyteller.qqq@0)/7104292957078701623
Could not resolve reference 'variableDeclaration' from myVar.
a910439a-d168-4aa5-9421-37d06025466a/r:c1c9a3cf-c88a-4327-9b7e-431420f47d76(storyteller.sandbox@transient13/storyteller.qqq@5_0)/7104292957078701623
-- cannot resolve reference by string: 'myVar'
-- was input: a910439a-d168-4aa5-9421-37d06025466a/r:55604285-5df7-43b6-9706-7cfc46d5e886(storyteller.sandbox@transient13/storyteller.qqq@0)/7104292957078701623
```
Currently I've managed to implemented it only by a pre-processing script that finds all instances of my statement where inner variable declaration is used, creates new `LocalVariableDeclarationStatement`, sets expression of my statement as initializer, and then (!) manually finds all variable references that are pointing to inner variable, and changes their target to the newly created local var.
But I don't like this approach very much.
What is the proper way to compile one variable declaration into another one, using proper templates, with all references staying intact?
Thanks in advance!
Please sign in to leave a comment.
It seems that main problem here is in the generation order, cuz I have another place where variables are generated, and references are resolved normally.
Difference is that in the second case I have a structure of two code blocks, that get compiled into two separate methods. Second block may reference variables from the first block. So when I generate those methods - I take all variables from the first block, and recreate them as local variables of the second generated method, initialized by arguments. In this case all references of the second block that was pointing to the variables of the first block are normally resolved to new declarations. I don't have to do anything special. And it seems that template of these two blocks gets generated before all of their children's.
But in the case, described in the main post, I have a separate statement, and its generation template. And it seems that generator creates a transient model where parent of the complex statement is already generated into another entity (so it cannot declare proper scope, for all the references to the complex statement), and the statement itself gets generated only after another couple of steps, when all the references are already broken and cannot be resolved.
Is it possible, or I do miss some key part in understanding if the generator process?
If this might be the case - what are the possible solutions?
May it be fixed with multiple generators and their priorities?
Thanks in advance!
Also a little question - how important is it to use multiple generators with priorities for the proper generation process?
I mean currently I have a single `main` generator descriptor where all of hundreds of my concepts are described.
Is it encouraged in any way to have multiple smaller generators in a single language, and to configure their priorities?
Thanks!
Hi Vantuz,
you typically use reference macros together with mapping labels in order to re-establish the connection between declaration and references to them after they get transformed during generation. With my limited understanding of your case I would expect a reduction rule for the variable reference to obtain the desired LocalVariableDeclaration from a mapping label.
Vaclav
You have quite a freedom in how you organize your generators. There might be some performance consequences, but the most important aspect to consider is the maintainability and extensibility. One giant set of rules may become messy at some point. On the other hand, separate generators require managing their dependencies and priorities.
In general, if you can see natural boundaries between parts of your generator, I would suggest splitting them.
Hi Vaclav,
Greatest thanks for the answers!
Mapping label and $MAP_SRC$ worked awesomely fine!
Thanks!