textx

Reference attribute in parent


I'm trying to write a small DSL for translating classes from one domain to another where the classes and attributes are mostly the same but with some attribute names may be different. For example, the meaning of an attribute is inverted.

Something like this:

class foo {
    boolean x_is_true
}

class bar {
    boolean x_is_false
}


translate foo to bar { // foo is src and bar is dest
    dest.x_is_false = not(src.x_is_true)
}

I have a grammar that looks like this so far:

Model:
    classes*=Class
    translations*=Translation
    ;

Class: 
    'class' name=ID '{'
        parameters+=Parameter
    '}'
    ;

Parameter:
    type=Type name=ID
    ;

Type:
    'boolean'
    ;

Translation:
    'translate' source=[Class] 'to' dest=[Class] '{'
        mappings+=Mapping
    '}'
    ;

Mapping:
    src=[Parameter|FQN|^classes*.parameters]
    ;

Comment: /\/\/.*$/;
FQN: ID('.'ID)*;

Which will work if I write the translation like so, just to get the reference:

translate foo to bar {
    bar.x_is_false
}

Can I write an RREL such that it will match a reference in the parent scope without repeating foo/bar? In real-world use the foo/bar will be much longer strings.


Solution

  • One way of doing this would be:

    Mapping:
        dest=Destination '=' src=Source
    ;
    
    Destination:
        'dest.' dest=[Parameter|FQN|...~dest.parameters]
    ;
    
    Source:
        'src.' src=[Parameter|FQN|...~source.parameters]
    ;
    
    

    and the translate part that match would be:

    translate foo to bar { // foo is src and bar is dest
        dest.x_is_false = src.x_is_true
    }
    

    So, here you use src to reference to the source class and dest to reference to the destination class like in your example.

    Of course, for your RHS in the translation you need a full expression language but this should get you in the right direction.

    If you need more complex scoping logic you can always take a full control by implementing scoping provider in Python.