加速器。缩进策略

Acceleo. Indent strategies

我正在为一个生成源代码的项目测试 Acceleo。在这个语言中,缩进非常重要。

我找到了 indent strategies 的指南,但我认为它已过时,因为它引用了 indentSpace 和 indentTab,而我在 Acceleo 3.5 版本中没有找到此说明。

我曾想过使用序列变量来存储缩进空格,但将此变量传递给所有模板非常复杂。

你知道更好的缩进策略吗?有参考吗?

在 Acceleo 中处理新行、缩进和空格有时会很棘手。您可以查看此页面:http://help.eclipse.org/juno/topic/org.eclipse.acceleo.doc/pages/reference/textproductionrules.html,它提供了文本规则制作。

另外,Acceleo 是 MOFM2T 标准(OMG 标准)的实现。规范本身也有补充信息:http://www.omg.org/spec/MOFM2T/1.0/PDF/

作为快速回答,模板调用 'remember' 调用时使用的缩进。

这是一个例子:

[template public generate(c : Class)]
[comment @main/]
[file (c.name, false, 'UTF-8')]
Class [c.name/]
    [c.ownedAttribute.gen()/] [comment using implicit iterator/]
[/file]
[/template]

[template public gen(p : Property)]
name=[p.name/], type=[p.type.name/]
                                    [comment notice the new line/]
[/template]

和同一个,但使用 for 而不是隐式迭代器:

[template public generate(c : Class)]
[comment @main/]
[file (c.name, false, 'UTF-8')]
Class [c.name/]
    [for (p : Property | c.ownedAttribute)]
    [p.gen()/]
    [/for]
[/file]
[/template]

[template public gen(p : Property)]
name=[p.name/], type=[p.type.name/] [comment no more new line/]
[/template]

这是生成的输出(在两种情况下):

Class MyClass
    name=attribute, type=MyInterface
    name=attribute2, type=Boolean
    name=attribute3, type=Char

编辑> 关于你关于缩进的新问题(关于这个线程的下一个答案)。您可以轻松地将缩进作为模板的一部分进行管理,但通常,您必须不惜一切代价避免找到通用模板,否则,这通常会导致脚本难以阅读和维护。

这是一个小例子,仍然使用 UML 作为使用递归模板的输入元模型。

输入test.uml

<uml:Model xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:uml="http://www.eclipse.org/uml2/4.0.0/UML" xmi:version="2.0" xmi:id="_wfUKcIkNEeWSIKoWblTvZg" name="HelloModel">
  <packageImport xmi:id="_wfUKc4kNEeWSIKoWblTvZg">
    <importedPackage href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#/"/>
  </packageImport>
  <packageImport xmi:id="_wfUKdokNEeWSIKoWblTvZg">
    <importedPackage href="pathmap://GENMYMODEL_LIBRARIES/GenMyModelPrimitiveTypes.library.uml#/"/>
  </packageImport>
  <packagedElement xsi:type="uml:Package" xmi:id="_wfUKeYkNEeWSIKoWblTvZg" name="TOP">
    <packagedElement xsi:type="uml:Class" xmi:id="_wfUKfIkNEeWSIKoWblTvZg" name="Class1">
      <ownedAttribute xmi:id="_wfUKf4kNEeWSIKoWblTvZg" name="a1">
        <type xsi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#//Boolean"/>
      </ownedAttribute>
      <ownedAttribute xmi:id="_wfUKgokNEeWSIKoWblTvZg" name="a2">
        <type xsi:type="uml:PrimitiveType" href="pathmap://GENMYMODEL_LIBRARIES/GenMyModelPrimitiveTypes.library.uml#//Char"/>
      </ownedAttribute>
    </packagedElement>
    <packagedElement xsi:type="uml:Package" xmi:id="_wfUKhYkNEeWSIKoWblTvZg" name="INNER">
      <packagedElement xsi:type="uml:Class" xmi:id="_wfUKiIkNEeWSIKoWblTvZg" name="Class2">
        <ownedAttribute xmi:id="_wfUKi4kNEeWSIKoWblTvZg" name="a1">
          <type xsi:type="uml:PrimitiveType" href="pathmap://GENMYMODEL_LIBRARIES/GenMyModelPrimitiveTypes.library.uml#//Double"/>
        </ownedAttribute>
        <ownedAttribute xmi:id="_wfUKjokNEeWSIKoWblTvZg" name="a2">
          <type xsi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#//Integer"/>
        </ownedAttribute>
      </packagedElement>
    </packagedElement>
  </packagedElement>
</uml:Model>

视觉展示在这里(您也可以浏览模型树):https://repository.genmymodel.com/vincent.aranega/test1

以及我使用的脚本:

[module example_stack('http://www.eclipse.org/uml2/4.0.0/UML')/]

[template public generate(m : Model)]
[comment @main/]
[file ('res.txt', false, 'UTF-8')]
[m.name/]
['['/]
    [for (p : Package | m.packagedElement.oclAsType(Package))   separator('\n,\n')]
    [p.gen()/][/for]

]
[/file]
[/template]

[template public gen(o : OclAny)/]
[template public gen(p : Package)]
Container [p.name/]
['['/]
    [for (o : OclAny | p.packagedElement)]
    [o.gen()/][if (p.packagedElement->asOrderedSet()->last() <> o)],[/if]

    [/for]
]
[/template]

[template public gen(c : Class)]
Module [c.name/]
['['/]
    In
    ['['/]
        [for (p : Property | c.ownedAttribute)]
        [p.gen()/][if (c.ownedAttribute->last() <> p)],[/if]
        [/for]
    ]
]
[/template]

[template public gen(p : Property)]
[p.name/] : [p.type.name/]
[/template]

并且输出:

HelloModel
[
    Container TOP
    [
        Module Class1
        [
            In
            [
                a1 : Boolean,
                a2 : Char
            ]
        ],

        Container INNER
        [
            Module Class2
            [
                In
                [
                    a1 : Double,
                    a2 : Integer
                ]
            ]

        ]

    ]    
]

我们的想法是为每个元素生成一个专用模板,而不是只生成一个通用模板。这样,您就可以控制递归调用和缩进。在这个脚本中,有一件事我并不引以为豪,那就是 ',' 的管理方式(使用 if 而不是 separator)。可能有更好的方法来做到这一点。

放更多信息。
对于迭代模板,@VincentAranega 的信息很有用,但我还没有找到任何在递归模板中缩进的策略。
我相信不可能定义一个 globar var 来存储缩进,并且没有标记所需缩进的功能,为此,您必须传递一个参数模板来通知缩进并在每个元素中放入一个子模板来构造缩进 space.
查看链接后,我测试了这个案例。我的结论:获得所需的输出并保持模板的可读性很棘手
输入模型:

<?xml version="1.0" encoding="UTF-8"?>
<hellomodel:Hellomodel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:hellomodel="http://es.bancopopular.osgi.hellomodel">
  <calls tabla="T1001PE" name="MODULO" codNotFound="sqlcode = 100">
    <entrada>
      <datos xsi:type="hellomodel:Columna" campo="MODULO-CAMPO1" nombre="CAMPO1"/>
      <datos xsi:type="hellomodel:Literal" campo="MODULO-CAMPO2" value="2"/>
    </entrada>
    <callCode>call modulo</callCode>
    <callCode>retorno</callCode>
  </calls>
  <calls tabla="T1001PE" name="MODULO2" codNotFound="sqlcode = 100">
    <entrada>
      <datos xsi:type="hellomodel:Columna" campo="MODULO2-CAMPO1" nombre="CAMPO1"/>
      <datos xsi:type="hellomodel:Literal" campo="MODULO2-CAMPO2" value="2"/>
    </entrada>
    <callCode>call modulo</callCode>
    <callCode>retorno</callCode>
  </calls>
</hellomodel:Hellomodel>

mtl文件:

[module generate('http://es.bancopopular.osgi.hellomodel')]

[template public generateElement(aHellomodel : Hellomodel)]
[comment @main/]
[file ('res.txt', false, 'UTF-8')]
[generateR (aHellomodel,0)/]
[/file]
[/template]

[template public generateR(ele : OclAny, count: Integer)]
[   indent(count)/][generate(ele)/] [for (child : OclAny | ele.eContents()) 
                                          before ('\n'+indent(count)+'[\n') 
                                          separator (',\n') 
                                          after ('\n'+indent(count)+']\n')][
                                            generateR (child,count+4)/] [/for]
[/template]

[template public indent(count: Integer)]
[let spaces : String = '                                                     '
    ][spaces.first(count)/][/let]
[/template]

[template public generate(ele : OclAny) ][ele.eClass().name/][/template]
[template public generate(ele : Call)   ]Module [ele.name/][/template]
[template public generate(ele : Entrada)]In[/template]
[template public generate(ele : Columna)]Col->[ele.campo/]=[ele.nombre/][/template]
[template public generate(ele : Literal)]Lit->[ele.campo/]=[ele.value/][/template]

生成文件:

Hellomodel
[
    Module MODULO
    [
        In
        [
            Col->MODULO-CAMPO1=CAMPO1,
            Lit->MODULO-CAMPO2=2
        ]

    ]
,
    Module MODULO2
    [
        In
        [
            Col->MODULO2-CAMPO1=CAMPO1,
            Lit->MODULO2-CAMPO2=2
        ]

    ]

]