textX: Как генерировать имена объектов с помощью ObjectProcessors? - PullRequest
2 голосов
/ 29 мая 2019

У меня есть простой пример модели, где я хотел бы сгенерировать имена для объектов правила Position, которым не было дано имя с as <NAME>.Это необходимо для того, чтобы я мог найти их позже с помощью встроенного поставщика области действия FQN.

Моя идея заключается в том, чтобы сделать это в объектном процессоре position_name_generator, но он будет вызываться только после всей модели.анализируетсяЯ не совсем понимаю причину этого, поскольку к тому моменту, когда мне понадобится объект Position в Project, объекты уже созданы, но процессор объектов не будет вызван.

Другая идея состояла бы в том, чтобы сделать это в настраиваемом поставщике области действия для Position.location, который сначала будет выполнять генерацию имени, а затем использовать встроенный FQN для поиска объекта Location.Хотя это сработает, я считаю это хакерским и предпочел бы избежать этого.

Каков будет textX способ решения этой проблемы?

(Пожалуйста, примите во внимание, что это толькомаленький пример. В действительности аналогичная функциональность требуется для довольно большой и сложной модели. Изменить это поведение с помощью сгенерированных имен невозможно, поскольку это требование.)

import textx


MyLanguage = """
    Model
        :   (locations+=Location)*
            (employees+=Employee)*
            (positions+=Position)*
            (projects+=Project)*
        ;

    Project
        :   'project' name=ID
            ('{'
                ('use' use=[Position])*
            '}')?
        ;

    Position
        :   'define' 'position' employee=[Employee|FQN] '->' location=[Location|FQN] ('as' name=ID)?
        ;

    Employee
        :   'employee' name=ID   
        ;

    Location
        :   'location' name=ID
            ( '{'
                (sub_location+=Location)+
            '}')?
        ;

    FQN
        :   ID('.' ID)*
        ;

    Comment:
      /\/\/.*$/
    ;                
"""

MyCode = """
    location Building
    {
        location Entrance
        location Exit
    }

    employee Hans
    employee Juergen

    // Shall be referred to with the given name: "EntranceGuy"
    define position Hans->Building.Entrance as EntranceGuy 
    // Shall be referred to with the autogenerated name: <Employee>"At"<LastLocation>
    define position Juergen->Building.Exit                  

    project SecurityProject
    {
        use EntranceGuy
        use JuergenAtExit
    }
"""


def position_name_generator(obj):
    if "" == obj.name:
        obj.name = obj.employee.name + "At" + obj.location.name


def main():
    meta_model = textx.metamodel_from_str(MyLanguage)
    meta_model.register_scope_providers({
        "Position.location": textx.scoping.providers.FQN(),
    })

    meta_model.register_obj_processors({
        "Position": position_name_generator,
    })

    model = meta_model.model_from_str(MyCode)
    assert model, "Could not create model..."


if "__main__" == __name__:
    main()

1 Ответ

2 голосов
/ 02 июня 2019

Что такое textx способ решить эту проблему ...

Вариант использования, который вы описываете, заключается в определении имени объекта на основе других элементов модели , включая ссылку на другие элементы модели. В настоящее время это не является частью какого-либо теста и вариантов использования, включенных в наш набор тестов и документ textx.

Процессоры объектов выполняются на определенных этапах во время построения модели (см. http://textx.github.io/textX/stable/scoping/#using-the-scope-provider-to-modify-a-model). В описанной настройке они выполняются после эталонного разрешения. Поскольку само имя, которое должно быть определено / выведено, требуется для эталонного разрешения, здесь нельзя использовать объектные процессоры (даже если мы позволим контролировать, когда выполняются процессоры объектов, до или после разрешения области действия, описанная установка все равно не будет работать).

Учитывая динамику загрузки модели (см. http://textx.github.io/textX/stable/scoping/#using-the-scope-provider-to-modify-a-model), , решение находится в поставщике области действия (как вы предложили). Здесь мы позволяем контролировать порядок эталонного разрешения, например что ссылки на объект, именуемый пользовательской процедурой, откладываются до тех пор, пока ссылки, необходимые для вывода / определения имени, не будут разрешены.

Возможное решение

Предварительный эскиз того, как ваш вариант использования может быть решен, обсуждается в https://github.com/textX/textX/pull/194 (с приложенной проблемой https://github.com/textX/textX/issues/193).. Этот текстовый PR содержит версию scoping.py, которую вы, вероятно, могли бы использовать для ваш проект (просто скопируйте и переименуйте модуль). Полноценное решение может быть частью textx TEP-001, где мы планируем сделать область видимости более управляемой для конечного пользователя.

Игра с этим абсолютно интересным вопросом открыла для меня новые аспекты для структуры textx.

  • имена, зависящие от содержимого модели (включая неразрешенные ссылки). Это разрешение имени, которое может быть отложено (в ссылочном PR, см. Ниже) с точки зрения нашей логики разрешения ссылок.
  • Еще более интересными являются последствия этого: Что происходит со ссылками, указывающими на местоположения, где обнаружены неразрешенные имена? Здесь мы должны отложить процесс разрешения ссылок, потому что мы не можем знать, может ли имя совпадение при разрешении ...

Ваш пример включен: https://github.com/textX/textX/blob/analysis/issue193/tests/functional/test_scoping/test_name_resolver/test_issue193_auto_name.py

...