Используя функцию компилятора Macros.TraverseExpr, наткнулся на некоторое неудобство работы с ней. Главное то что невозможно выяснить в функции анализа, в каком контексте мы находимся, если анализируется PExpr.Ref например, он может быть идентификатором, частью присвоения, в квазицитате и где угодно. Если решение анализа требует верной обработки одного выражения например PExpr.Ref в разных контекстах, например в PExpr.Call, PExpr.Indexer, PExpr.Quoted то в функции анализа, которая вызывается из TraverseExpr невозможно определить в каком выражении находится текущий Ref, если находить родительские выражения матчить родительское выражение то при обработке до (флаг after : bool функции), мы не можем вернуть новое выражение (оно игнорируется), если обработать это выражение после то оно обрабатывается после его составных частей то есть PExpr.Call обрабатывается после связанных с ним Ref, то в Ref невозможно узнать где мы находимся в общем выражении или где.
Остается только либо сохранять информацию об этом mutable флагами или обходить по нескольку раз для каждого из вариантов трансформации.
Я думаю может быть стоит сделать расширение этой функции чтобы возможно было узнавать контекст, родительское выражение и все что до него в функции обработки экспрешена, для этого вместо параметра in_match надо сделать полноценную структуру контекст с информацией о родительском PExpr, тогда в один обход будет возможно узнать в каком участке кода мы находимся. Может кто нибудь посоветует как лучше в данном случае использовать эту функцию для сложного анализа и трансформации и как лучше модернизировать ее?
Здравствуйте, CodingUnit, Вы писали:
CU>Используя функцию компилятора Macros.TraverseExpr, наткнулся на некоторое неудобство работы с ней. Главное то что невозможно выяснить в функции анализа, в каком контексте мы находимся, если анализируется PExpr.Ref например, он может быть идентификатором, частью присвоения, в квазицитате и где угодно. Если решение анализа требует верной обработки одного выражения например PExpr.Ref в разных контекстах, например в PExpr.Call, PExpr.Indexer, PExpr.Quoted то в функции анализа, которая вызывается из TraverseExpr невозможно определить в каком выражении находится текущий Ref, если находить родительские выражения матчить родительское выражение то при обработке до (флаг after : bool функции), мы не можем вернуть новое выражение (оно игнорируется), если обработать это выражение после то оно обрабатывается после его составных частей то есть PExpr.Call обрабатывается после связанных с ним Ref, то в Ref невозможно узнать где мы находимся в общем выражении или где.
Идеальным для вас вариантом было бы добавить в PExpr ссылку на своего "родителя" в дереве. Но я не уверен, что это будет безвредно для производительности компилятора, которая и сейчас не вызывает комплиментов.
CU> Я думаю может быть стоит сделать расширение этой функции чтобы возможно было узнавать контекст, родительское выражение и все что до него в функции обработки экспрешена, для этого вместо параметра in_match надо сделать полноценную структуру контекст с информацией о родительском PExpr, тогда в один обход будет возможно узнать в каком участке кода мы находимся.
Альтернативно, создать отдельное дерево "родительских" отношений между PExpr-ами внутри тела метода и получать контекст уже по нему.
def tree = CreateBodyTree(currentMethod);
...
// во время обработки конкретного PExpr-а
def parent = tree.GetParent(expr);
def grandParent = tree.GetParent(parent);
def defs = tree.FindChildren(expr, _ is <[ def $x = $y ]>); // а че, почему бы и такую функцию не добавить
CU> Может кто нибудь посоветует как лучше в данном случае использовать эту функцию для сложного анализа и трансформации и как лучше модернизировать ее?
По моему опыту написания аж двух
general-purpose макросов, лучше всего выдрать код из компилятора, оформить в отдельный макропроект, переписать по вашему усмотрению, и после дискуссии с сообществом закоммитить назад в Nemerle
Позитивы:
1. практика написания макросов
2. будете точно знать, как работает конкретный макрос из стандартной библиотеке
3. сделаете Nemerle лучше
Здравствуйте, catbert, Вы писали:
C>Идеальным для вас вариантом было бы добавить в PExpr ссылку на своего "родителя" в дереве. Но я не уверен, что это будет безвредно для производительности компилятора, которая и сейчас не вызывает комплиментов.
да, я уже дискутировал по этому вопросу с Владом, он говорит что так дерево станет изменяемым, потому что дети создаются раньше родителей, и ссылку придется добавлять после создания детей конструктором
CU>> Я думаю может быть стоит сделать расширение этой функции чтобы возможно было узнавать контекст, родительское выражение и все что до него в функции обработки экспрешена, для этого вместо параметра in_match надо сделать полноценную структуру контекст с информацией о родительском PExpr, тогда в один обход будет возможно узнать в каком участке кода мы находимся.
C>Альтернативно, создать отдельное дерево "родительских" отношений между PExpr-ами внутри тела метода и получать контекст уже по нему.
если это решение должно быть универсальным, то место этой функции в библиотеке компилятора, это почти аналогично созданию новой функции TraverseExpr с возможностью узнавать контекст, только узнавать parent в самой функции, проще чем строить новое дерево
C>По моему опыту написания аж двух general-purpose макросов, лучше всего выдрать код из компилятора, оформить в отдельный макропроект, переписать по вашему усмотрению, и после дискуссии с сообществом закоммитить назад в Nemerle
мне этот вариант нравится больше, вот только теперь думаю как лучше сделать контекст, который будет передаваться параметром в функцию анализа, если это будет ссылочный класс, то потребуются накладные расходы на его создание, удаление. Можно структурой с PExpr показывающим текущее выражение и ссылкой на эту же структуру родителя, можно перечислением, в нем можно узнать некий универсальный контекст, но нельзя узнать всю иерархию из ссылок на родителей. Наверное вариант со структурой более оптимален?