![]() |
:property modifiable by generator? |
Post Reply
|
| Author | |
mpierce
Member
Joined: 22.Jul.2010 Location: Cheney, WA, USA Points: 9 |
Post Options
Thanks(0)
Quote Reply
Topic: :property modifiable by generator?Posted: 05.Aug.2010 at 10:17 |
|
Hello all,
is it possible to modfied the value of a :property from within a code generator? I've got an object that I'm using to terminate an if-then-else statement, called an if-terminator (where the then and else sections converge back together) and I'm trying to find a way to mark it as having been visited by the 'then' path so that it terminates for the 'then' path but is passed through by the 'else' path. I've made a :Visited count; property but I can't seem to be able to change it's value from within a code generator - is there a way to do this?
Thanks,
Matt
|
|
![]() |
|
stevek
MetaCase
Joined: 11.Mar.2008 Points: 643 |
Post Options
Thanks(0)
Quote Reply
Posted: 05.Aug.2010 at 10:58 |
|
Access to models from within a MERL generator is read-only. The API can be used for read-write access (as well as creation and deletion), but for your case there's a better way. Your "Visited count" property shouldn't be persistent information - it's something you want to store only during a given generator run. The easiest way is probably to maintain a MERL variable containing the unique id of each if-terminator that you have encountered. When you meet an if-terminator, check if its id is matched in the variable and if so ignore it. If not, add it to the variable and process it. There are several examples in the demo repository - use Advanced Find in the Generator Editor to look for %wildsp.
$visited = ' '
subreport '_translators' run
/* insert statements here to navigate to an if-terminator */
if not $visited =~ oid%wildsp then
variable 'visited' append oid ' ' close /* insert statements here to process the if-terminator */
endif
An alternative solution would be to change your modeling language to have a structure less like a flowchart and more like an abstract syntax tree. This is explained on p288-290 in the DSM book; hopefully the following picture will show the basic idea.
![]() Edited by stevek - 05.Aug.2010 at 10:58 |
|
![]() |
|
mpierce
Member
Joined: 22.Jul.2010 Location: Cheney, WA, USA Points: 9 |
Post Options
Thanks(0)
Quote Reply
Posted: 06.Aug.2010 at 01:19 |
|
OK, this almos works :) Here's a snippet of my code:
else if type = 'If terminator'; then
'}' newline subreport '_translators' run /* I've run this once at startup, doesn't seem to make a diff */ if not ($visited =~ oid%wildsp) then variable 'visited' append oid ' ' close else do ~Statement; where #Out of statement port { do ~Statement.() { subreport 'Process Body Generator' run } } endif No matter what happens, it always thinks that oid does not have the object's oid in it (I've verified in the debugger window that the oid value is infact being set in variable "visited", any ideas as to why the "if not ($visited =~ oid%wildsp) then" always thinks the oid is not in the variable, even when it is?
Thanks,
Matt
|
|
![]() |
|
mpierce
Member
Joined: 22.Jul.2010 Location: Cheney, WA, USA Points: 9 |
Post Options
Thanks(0)
Quote Reply
Posted: 06.Aug.2010 at 01:25 |
|
Oops, I meant to say "No matter what happens, it always thinks that variable visited does not have the object's oid in it "
Also, the parens around the comparison don't make a difference.
|
|
![]() |
|
mpierce
Member
Joined: 22.Jul.2010 Location: Cheney, WA, USA Points: 9 |
Post Options
Thanks(0)
Quote Reply
Posted: 06.Aug.2010 at 01:36 |
|
I was thinking of something similar to your second solution (abstract tree) but I'm going to try the oid route first and then maybe the abstract tree route later. --Matt
|
|
![]() |
|
mpierce
Member
Joined: 22.Jul.2010 Location: Cheney, WA, USA Points: 9 |
Post Options
Thanks(0)
Quote Reply
Posted: 06.Aug.2010 at 08:31 |
|
I've verified that "if not $visited = oid then" works (but only for singly nested if statements)
and
"if not $visited = oid%wildsp then" does not work for me. I've run the _translator report from the main generator, from withing sub generators, and right before the if statement but it doesn't recognize the oid being in the 'visited' variable. I've used the _translators subreport as-is as well as copied out the %wildsp part and embedded it in my code.
Is there some other variable or flag or setting I need to enable to make this work?
Thanks,
Matt
|
|
![]() |
|
stevek
MetaCase
Joined: 11.Mar.2008 Points: 643 |
Post Options
Thanks(0)
Quote Reply
Posted: 06.Aug.2010 at 11:32 |
|
Based on what you've posted, your problem is that you've changed =~ to = and maybe missed initializing $visited to a single space. But let's break it down to be sure:
$visited is going to contain something like this after you have visited three terminators:
' 3_1234 3_5678 3_2468 '
oid will be something like '3_5678' if you're revisiting the 2nd
oid%wildsp will add spaces and stars to get '* 3_5678 *'
=~ will perform a wildcard match (I notice in your later posts you just used =, which won't work).
Note the initialization of $visited to a single space, ' ', so oid%wildsp will match even for the first object.
_translators only needs to be run once, right at the start of your generator. It just defines %wildsp etc., and those definitions will last until the end of the generator run.
|
|
![]() |
|
mpierce
Member
Joined: 22.Jul.2010 Location: Cheney, WA, USA Points: 9 |
Post Options
Thanks(0)
Quote Reply
Posted: 06.Aug.2010 at 20:40 |
|
OK, the root problem was that I was initializing $visited with '' instead of ' ', the other things noted above were actually symptoms of my hacking around trying to make it work. Once I initialized visited with a space things work properly and now my code generators work properly - thanks so much for your help.
Do you have suggestions for best handling indentation of output? I've made a subreport called _indent and have a variable that I increment and decrement as indention changes and which is used by _indent. I execute _indent before every line of output. I suppose I could have a indent variable that I add/subtract spaces to/from and print out before every line of output, but I'm looking for additional suggestions.
Thanks again,
Matt
|
|
![]() |
|
stevek
MetaCase
Joined: 11.Mar.2008 Points: 643 |
Post Options
Thanks(0)
Quote Reply
Posted: 07.Aug.2010 at 12:02 |
|
For indentation, try looking at the 'indent' translator, which turns each newline into a newline plus tab. The nice thing is that it can be used in recursive generators, and the recursion depth takes care of how many tabs there are:
Report '_recurse'
to 'indent' translate
newline 'first line'
newline 'second line'
if $++ix < '5' NUM then
subreport '_recurse' run
endif
endto
endreport
Report 'indent'
subreport '_translators' run
$ix='0'
subreport '_recurse' run
endreport
It's not ideal to require the newline at the start of a line of code rather than the end, but I haven't tried messing around with a smarter regex version.
Your variable is also a reasonable way. Rather than having an integer variable and implementing a "for" loop in MERL (e.g. by recursion as above), you could have a string variable containing the tabs, and use a translator to add or remove one as necessary.
|
|
![]() |
|
Post Reply
|
|
| Tweet |
| Forum Jump | Forum Permissions ![]() You cannot post new topics in this forum You cannot reply to topics in this forum You cannot delete your posts in this forum You cannot edit your posts in this forum You cannot create polls in this forum You cannot vote in polls in this forum |