MetaCase Homepage
Forum Home Forum Home > > MetaEdit+
  New Posts New Posts RSS Feed - Using local name with Merl
  FAQ FAQ  Forum Search   Events   Register Register  Login Login

Using local name with Merl

 Post Reply Post Reply
Author
Message
MerlUser View Drop Down
Member
Member


Joined: 13.Jul.2010
Location: Germany
Points: 3
Post Options Post Options   Thanks (0) Thanks(0)   Quote MerlUser Quote  Post ReplyReply Direct Link To This Post Topic: Using local name with Merl
    Posted: 13.Jul.2010 at 18:17

How can i access the "local name" of a property?

With the following code, I was able to make a list of properties with the type-name and its value, but in my case there are more than one property of the same type (but with different local names):
 
foreach .() {
  '<' type%var 
  do :() {
   ' ' type%var '="' id%xml '"'
  }
  ' />' newline
}
 
Here is an example output:
 
<state typeA="a" typeB="b" typeA="c" />
 
In XML-files it is not allowed to define different attributes with the same name. The local names of the properties in the metaedit object have already different names. So i want to use these local names of the metaedit object properties, but how can I use these local names from merl?
Back to Top
stevek View Drop Down
MetaCase
MetaCase
Avatar

Joined: 11.Mar.2008
Points: 643
Post Options Post Options   Thanks (0) Thanks(0)   Quote stevek Quote  Post ReplyReply Direct Link To This Post Posted: 16.Jul.2010 at 02:20
It looks like you're trying to write a generic generator, i.e. one that can be used for any metamodel. They are actually rather hard, because you need reflection capabilities to read the metamodel information. A normal generator only needs to read the model information, and the generator itself contains direct references to particular types, local names etc.

If you really want your model transformed in a watertight way into XML, I'd suggest you look instead at MetaEdit+'s XML export. That already takes care of the many XML challenges such as object references, circularity, illegal characters etc. that you will face after overcoming this hurdle. It should be easy enough to massage the XML export format into the format you want, e.g. with XSLT.

On the other hand, if this was just a quick example to play around with MERL, I'd suggest you look at a different task. For a generator to add value, it has to understand the different semantics of each piece of information in the models, rather than just treating them all the same. For instance, normally one property will go to make up the name of a file, another to become a function name, still another will become part of a condition. Each property will thus be named explicitly in the generator, rather than iterating over all of them with "do :()".

If you really want the local names, MERL doesn't have direct access to them [Edit 2018: now it does!]: it's designed to operate on models, not metamodels. You can however get them by saving the metamodel into text with:
   internal 'document:into: "' type '" metamodels' execute
and reading that into a variable with:
   variable 'metamodel' write
      filename 'metamodels' sep type sep 'metamodel.txt' read
   close
You can then iterate over the lines of that variable with "do $metamodel" - you'll have to do a little processing, but you can look at the "Reverse engineer Java" generator in UML's Class Diagram for hints.

Of course, if you're only going to do this for one metamodel, there's no need to write a metaprogram that could do it for all metamodels. Just stick direct references to the local names into the generator: it's almost certainly faster in the long run, and also gives you a measure of indirection to cope with name changes in the future (e.g. if you want to keep the same XML schema but make the user-visible names in the modeling tool more user-friendly).

do .State {
'<state name="' :Name%xml '" description="' :Description%xml '/>' newline
}

Note how that is already simpler than what you have above, and easier to read. I'm a big fan of meta solutions, but even I have to admit that in some cases a simple solution, even one with some apparent duplication, may be best!

Edited by stevek - 29.May.2018 at 09:29
Back to Top
MerlUser View Drop Down
Member
Member


Joined: 13.Jul.2010
Location: Germany
Points: 3
Post Options Post Options   Thanks (0) Thanks(0)   Quote MerlUser Quote  Post ReplyReply Direct Link To This Post Posted: 19.Jul.2010 at 13:26
Thanks a lot for your detailed reply.

Yes, I would like to write a generic generator, because my meta-model contains a specific relation on which several different objects are connected. It would be nice to iterate over these objects and its properties in a generic way to write all the data to a XML file.

It would be very nice to have access also to the local name. The interpreter of merl is already able to iterate over all properties and gives access to "type" and "value". I am thinking of a key word like "localname" for having access to the local name of a property.
In my opinion it would be easy for you to add this to the merl-language, isn't it?

Back to Top
stevek View Drop Down
MetaCase
MetaCase
Avatar

Joined: 11.Mar.2008
Points: 643
Post Options Post Options   Thanks (0) Thanks(0)   Quote stevek Quote  Post ReplyReply Direct Link To This Post Posted: 22.Jul.2010 at 14:52
It actually wouldn't be trivial to add local name: inside do :(), the elements we are iterating over are properties. A property doesn't know its local name, because the same property can be shared between several objects, maybe of different types or in different slots, each with its own local name.
 
While we can work around that, adding "localName" opens up a large number of other new commands that would then be needed, e.g. to find the datatype of the property type to know whether to recurse again with do :() over a contained object or collection; to find the supertype of the current type; to find the kind of List widget a property type uses and its legal values etc. Essentially, MERL is a language for navigating models, and doesn't have commands to navigate metamodels. Adding those commands would increase the size of MERL by at least 50% - and the topic next to yours in the forum shows that some people already need to take a big breath before getting started.
 
Of course, we recognise the desire to write meta-programs in MERL, and indeed we use that freely in some areas (e.g. subreport '_' type run). While there is a little duplication involved in writing local names explicitly in generators, as well as in the metamodel, that's only for one person - the metamodeler - and not for all the modelers. Unless you have hundreds of types with dozens of properties each, that shouldn't be too bad.
 
BTW Maybe one solution for you, if all you need is uniqueness of attribute names, would be to add a number to the end of the name:
 
$ix='0'
do :() { ... type%var $++ix ...}
Back to Top
MerlUser View Drop Down
Member
Member


Joined: 13.Jul.2010
Location: Germany
Points: 3
Post Options Post Options   Thanks (0) Thanks(0)   Quote MerlUser Quote  Post ReplyReply Direct Link To This Post Posted: 26.Jul.2010 at 14:59
The last example you give is not the best solution, but it works for my problem.

Now I changed the most type names of the properties to the local name. Only in cases where are more than one properties with the same type, I add extra code like this:

do :() {
   if type<>'exceptionType' then
      ' ' type%var '="' id%xml '"'
   endif
}
' exceptionOne="' :exceptionOne%xml '"'
' exceptionTwo="' :exceptionTwo%xml '"'
Back to Top
stevek View Drop Down
MetaCase
MetaCase
Avatar

Joined: 11.Mar.2008
Points: 643
Post Options Post Options   Thanks (0) Thanks(0)   Quote stevek Quote  Post ReplyReply Direct Link To This Post Posted: 26.Jul.2010 at 15:15
Great! That's a nice combination of a meta-solution with pragmatism.
 
Pragmatism is definitely needed when working with XML. It looks simple, but actually the full rules are a nightmare, so trying to write code on day 1 that fulfills all the rules is a lost cause. E.g. how many remember that the name of an attribute cannot start with the letters "xml" in any combination of cases, but it can start with a colon?
Back to Top
djuka View Drop Down
Major Contributor
Major Contributor
Avatar

Joined: 22.Jun.2011
Location: Germany
Points: 33
Post Options Post Options   Thanks (0) Thanks(0)   Quote djuka Quote  Post ReplyReply Direct Link To This Post Posted: 16.Feb.2012 at 10:35
Hello !

"In protocols" is property defined as collection. I could not find how to iterate
over collection members. For me is not problem to get metadata, this can be
fixed, but iterating over elements is important. If I use id complete collection
is printed.

Any idea how to solve this problem in MERL (and MetaEdit+ beta 5.0).

MERL:

if type ='In protocols' then
'    void On' id '()' newline       
endif   


Output:

void OnIn:HasContact[Boolean] In:FullPress[Boolean] In:CurrPos[double]

Regards,
Djuka
Back to Top
janne View Drop Down
MetaCase
MetaCase
Avatar

Joined: 25.Mar.2008
Points: 58
Post Options Post Options   Thanks (0) Thanks(0)   Quote janne Quote  Post ReplyReply Direct Link To This Post Posted: 16.Feb.2012 at 11:08
Hi,

How about iterating the collection with:

'   void On'
do :In protocols; { id ' '} newline


Or (if you don't want to have extra space after the last reported item)

'   void On'
dowhile :In protocols; { id ' '} newline

While in your sample you have metatype testing for the property field, I assume you are iterating over all properties (have do :() {...}). If that is the case, then you need to index the inner do loop with 1, following sample should work:

do :() {
  if type ='In protocols' then
    ' void On'
    dowhile :In protocols;1 {id ' ' } newline
  endif
}

More samples and full MERL documentation can be found from: http://www.metacase.com/support/45/manuals/mwb/Mw.html


Edited by janne - 16.Feb.2012 at 11:10
Back to Top
djuka View Drop Down
Major Contributor
Major Contributor
Avatar

Joined: 22.Jun.2011
Location: Germany
Points: 33
Post Options Post Options   Thanks (0) Thanks(0)   Quote djuka Quote  Post ReplyReply Direct Link To This Post Posted: 16.Feb.2012 at 11:56
Yes, that's it !

Thanks a lot !

This generates C++ classes:

MERL:

Report 'Controlers'

foreach .Actor;
{   
    if :IsControler; = 'T' then
        '#ifndef C_' :Name;'_HEADER_H_' newline
        '#define C_' :Name;'_HEADER_H_' newline
        newline
'Class C' :Name; newline
    '{
    public:'
    newline
    '    C' :Name; '(TSensorValue min,TSensorValue max,TSensorValue curr) : CGenericSensor(min,max,curr)
    {
        //TODO: ???
    }' newline
    '    virtual~C' :Name; '(void) {   
    }'

    newline
    '    void On' :Name; 'Press() {
        sensorDown();
    };'
    newline
    '    void On' :Name; 'Release() {
        sensorUp();
    };'
    newline
    '// Declaration of event handlers' newline
    do :();
    {
        if type ='In protocols' then
        do :In protocols;1
        {
            '    void On' :Signal name; '();' newline       
        }
        endif   
    }
    newline
    '// Declaration of members' newline
    do :();
    {
        if type ='In protocols' then
        do :In protocols;1
        {
            :Data type; ' m_' :Signal name; ' = ' :Default value;';' newline
        }
        endif   
    }
    newline
   
    '#endif'
   
    newline
    newline   
   
    endif
}
endreport


Output:
#ifndef C_TempoLimitController_HEADER_H_
#define C_TempoLimitController_HEADER_H_

Class CTempoLimitController
{
    public:
    CTempoLimitController(TSensorValue min,TSensorValue max,TSensorValue curr) : CGenericSensor(min,max,curr)
    {
        //TODO: ???
    }
    virtual~CTempoLimitController(void) {   
    }
    void OnTempoLimitControllerPress() {
        sensorDown();
    };
    void OnTempoLimitControllerRelease() {
        sensorUp();
    };
// Declaration of event handlers
    void OnOnOff();
    void OnSpeedCurr();

// Declaration of members
Boolean m_OnOff = false;
int m_SpeedCurr = 0;

#endif

Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down

Forum Software by Web Wiz Forums® version 12.05
Copyright ©2001-2022 Web Wiz Ltd.

This page was generated in 0.054 seconds.