I generate a name in a weave, How can I reference it in a reduction?

  • Open the attached project in MPS 2.0 build 20.7566
  • Right click "sandbox" and select "Preview Generated Text"
You will see 5 uniquely named Woven Thing2s and 5 reductions that don't yet reference the name
  • Open "main" from in the Generator
  • Open the inspector for the property macro around "Name" in the reduction rule for "Thing2"
  • Swap comments to comment out the second line and uncomment the first
    - Make the language
  • Right click "sandbox" and select "Preview Generated Text"
You will see 5 instances of "'get output by input and label' cannot be used here"

I would like to be able to reference the things I generated in the weave from reductions. This is a simplified version of what I'm trying to do in my full project. How should I accomplish this?



LabelTest.zip (62KB)
Weavings are applied after reduction rules.

Each minor step transforms input model into output. It consists of:

1. Building output model node structure.
      a. applying 'create root' rules
      b. applying 'root mappings'
      c. copying the rest into the output model
2. Applying weaving rules.
3. Applying post-processing stuff (see $MAP_SRC$ -> post processing).
4. Restoring references (invokes reference macro code).

PS: In MPS 2.0 you can use $WEAVE$ macro instead of weaving rules. It annotates the target node and you have to provide input nodes query.
Okay, so it sounds like the error message is leading me astray a bit. It's not that I can't use 'get output by input and label' in a reduction, but I can't look up a label I set in a weave in a reduction.

I tried using the $WEAVE$ macro instead of a weave rule and get the same problem.

I'm not sure you answered my question. What is the proper way to accomplish this? Should I be generating the unique name where I reference it and assigning that to a label, then looking it up when I generate the thing to be named so it happens in the right order?

This seems like a fairly common thing to need to do. The real case is I'm generating C++ (GText) and I have a construct that needs to generate some code where it is and also generate a class off to the side somewhere to be referenced from the code generated in place.


Here's the project using $WEAVE$ instead: LabelTest2.zip (62KB)
I tried reversing the thing and generating the unique name in the reduction where I reference the class, and then having the class look up the name that was generated, but I actually get the same error. It seems there's more going on than just the ordering of the generation steps?

Here's the project with them reversed: LabelTest3.zip (62KB)
I see in the tutorial the labels are used w/in the generation of a single item (http://www.jetbrains.com/mps/docs/tutorial.html#Implementing_generator). Is this the only supported use for them? Can they not be used in different generation steps?
I pulled up the source code and I see that the error is generated at TemplateQueryContext.java:115 if "areMappingsAvailable".

"areMappingsAvailable" is at TemplateGenerator:668 and is true if !myStrictMode or "myAreMappingsReady".

myStrictMode seems to be false by default, but is apparently true when I run the generator, so then examining areMappingsAvailable I find that during "apply" (TemplateGenerator.java:89) it gets set to false while applying reductions. Does this mean you can't look up labels when applying reductions? Is there a reason for that, or am I misreading the code?
Okay, by experimenting with the calculator tutorial I have figured out that you _can_ lookup labels in reference macros in reductions, but not in (for example) property macros...
Exactly! Reduction rules can be applied in parallel. So we forbid reading labels while building the output tree. References are restored afterwards, when mapping labels are available. Note, that weaving rules are still applied in one thread and labels are available for reading and creating. The more weaving rules you use the worse is the performance of your generator.

In non-strict mode (compatibility mode for old projects) we cannot generate incrementally or in parallel.
Okay, I'm getting a better picture of what I can't do, but I'm still not sure I've had my question answered which is how do I accomplish what I'm trying to do?

Here's what I think I've learned so far:

  • I can create labels anywhere
  • I can read labels in weave rules that were created in reductions/roots
  • I can read labels created anywhere in reference macros

What I'm trying to do isn't very compatible with these restrictions. To sum it up again:

  • I'm generating to Cxx using GText, I'm not using baseLanguage or extending any other languages
  • I have a Concept called AnonymousFunction
  • I want to generate a GText/Cxx class off to the side with a unique name for each AnonymousFunction in a certain tree of expressions
    • I've done this in two ways while experimenting, one as a weave, and one that searches descendants for AnonymousFunctions and generates them in the root rule. I prefer the former.
  • I want to generate some stuff from the site of the AnonymousFunction to instantiate an instance of the class for which I need the name of the class.
    • I need to look up the label while doing this. Apparently the only way is within a reference macro.

I think what I need is an additional concept that my AnonymousFunction reduces to which contains the information from the AnonymousFunction plus a reference to the node I can get the name from. I can then use a reference macro to read the label and create another reduction for that concept that finally brings it down to GText. This seems to me like a workaround. Any better ideas? I'll try to modify my LabelTest example to work this way and see what happens.
We have very similar functionality in baseLanguageInternal. The concept is called ExtractStaticMethodExpression (and ExtractStaticMethod_CallExpression). It allows to annotate an expression with a method and immediately call it. During generation method gets an unique name (if required) and is extracted into the top level classifier. We use it mostly in generators.

1. weaving rule extracts method, gives it a name, and stores it under a label
2. ExtractStaticMethod_CallExpression is reduced into static method call, reference to extracted method is get from the mapping label in reference macro
Or, you can create a pre-processing script, annotating AnonymousFunction with an unique name.

There are several ways to annotate node.

1. (model way) create a concept extending NodeAttribute, set concept property: role = nameAnnotation, set concept link: attributed = AnonymousFunction

create editor: [- nameAttribute(name={name}) [>attributed node<] -]

2. node/.putUserObject("nameAttribute", "...")

3. (generator only way) genContext.transient object [ "name for: " + node/.getId() ] = ...;
Great, thanks for the ideas. I think I like #2 the best (I think it's generator only too). I'll give it a try and also look at the example you cited. This should be enough to get me unblocked. Thanks!
heh, okay what does node/ mean? I see putUserObject on SNode, but I don't see it in the popup list when trying to add it to a node, and I don't see any uses of it globally...
Nevermind figured it out. I had to import the smodel models and have successfully gotten method #2 working! woo! I'm unblocked.

Btw I tried adding the extra concept and reducing to it and then reducing that to what I wanted so I could use a reference macro, but I'm generating to GText, and I can't reduce to something that isn't in GText. I guess I'd have to extend GText and make the thing extend something in GText, but wow that's a lot of working around, I'll stick w/ method #2.

Thanks for the help!
/ is downcast operation. It "casts" node<> to SNode (which is a target type)

node<> node = ...;   // node<> is smodel type
SNode nodeAsSNode = node/;  // SNode is lower level java type

Please sign in to leave a comment.