Замена типов в негодяях АСТ - PullRequest
0 голосов
/ 29 ноября 2018

Я пытаюсь заменить все типы в AST.Анализ языка Java с использованием модели m3; определения отсюда

Если мы возьмем этот код:

Int a = 1;

Я могу обновить тип 1, например, void.Но я не могу изменить тип самой переменной.

Я включил несколько примеров строк.Кто-то может указать на ошибки в строках?

case \method(Type \return, str name, list[Declaration] parameters, list[Expression] exceptions)
    => \method(\int(), "funcHolder", parameters, exceptions)

case \type(Type \type) => \void()
case \type => \void

1 Ответ

0 голосов
/ 30 ноября 2018

Хорошо, отличный вопрос.Сначала ваш код и возможные ошибки:

Это выглядит хорошо:

case \method(Type \return, str name, list[Declaration] parameters, list[Expression] exceptions)
    => \method(\int(), "funcHolder", parameters, exceptions) 

Определение: data Declaration = \method(Type \return, str name, list[Declaration] parameters, list[Expression] exceptions, Statement impl); (см. здесь ) и ваш кодточно соответствует определению.Каждое объявление abstract в проанализированных вами AST будет соответствовать этому, так как есть еще одно объявление \method для методов с телами с дополнительным аргументом.

Возможно, в вашем примере кода нет тел абстрактных методов, в этом случае это ничего не делает.

Более простая версия также будет работать нормально:

case \method(_, _, parameters, exceptions) => \method(\int(), "funcHolder", parameters, exceptions)

Следующая имеет проблемы:

case \type(Type \type) => \void() 

Поскольку data Expression = \type(Type \type), то есть Expression иdata Type = \void(), то есть Type или data TypeSymbol = \void(), это TypeSymbol, перезапись не сохраняет тип и будет делать неправильные вещи, если компилятор Rascal не обнаружит это.В основном это, вероятно, не будет работать для вас, потому что ваш пример кода не содержит этого конкретного вида выражения.Я подозреваю, что это может быть абстрактная запись для таких вещей, как int.class и Integer.class.

Тогда эта "интересная":

case \type => \void() 

В принципе, если \ typeне привязан в текущей области видимости, тогда это соответствует буквально чему-либо.Но, вероятно, есть функция с именем \ type или переменная или что-то еще, и, таким образом, этот шаблон проверяет равенство с другими объектами в области видимости.Очень противно!Это не будет соответствовать ни с чем, я бы догадался.Кстати, мы планируем «Предложение по изменению мошенничества» для изменения языка, чтобы избежать таких случайных привязок вещей в рамках шаблона.

Позже из комментариев я узнал, что цель состояла в том, чтобы заменить все экземпляры Type в AST на void(), чтобы помочь в обнаружении клонов имен по модулю.Это делается следующим образом:

case Type _ => \void() 

Мы используем шаблон [TypedVariable] с именем переменной _, чтобы соответствовать любому узлу алгебраического типа Type и забыть о привязке.Затем этот узел будет заменен на void().

Мой метод работы при отсутствии вспомогательного инструмента для сопоставления с образцом заключается в следующем:

  1. найти полный ASTнапример, что-то, что вы хотите сопоставить, скажем Int a = 1;
  2. скопируйте его в исходный файл Rascal
  3. удалите части, из которых вы хотите абстрагироваться, введя переменные или _
  4. test на оригинальном примере
  5. test на остальной системе, распечатав loc, которые соответствуют, и нажав на locs, чтобы привести вас к коду и посмотреть, не является ли он ложнымположительный.

например, я хочу переписать Int в void, я нахожу пример Int в AST и вставляю его:

visit (ast) {
   case simpleType(simpleName("Int")) => Type::\void()  // I added Type:: to be sure to disambiguate with TypeSymbol::void()
}

Снекоторый отладочный код, прикрепленный для распечатки всех совпадений:

visit (ast) {
   case e:simpleType(simpleName("Int")) => Type::\void()  
     when bprintln("found a type at <e.src?|unknown:///|>");
}

Может быть, вы обнаружите, что совпадений слишком много, и вам нужно стать более конкретным, поэтому давайте изменим только объявления Int _ = ....;, мы сначалавозьмите пример:

\variables(simpleType(simpleName("Int")), [...lots of stuff here...])

, а затемупростите его:

\variables(simpleType(simpleName("Int")), names)

и затем включите его в посещение:

visit (ast) {
   case \variables(simpleType(simpleName("Int")), names) => \variables(Type::\void(), names) 
}

Последнее замечание: вы можете видеть, что вы можете вкладывать шаблоны настолько глубоко, насколько захотите, поэтому любая комбинацияЭто хорошо.«Сложный» пример:

\variables(/"Int", names)

Этот шаблон находит любое объявление переменной, где имя «Int» используется где-то как часть объявления типа.Это более свободно, чем наш оригинал и может поймать больше, чем вы рассчитывали.Это просто, чтобы показать, какие комбинации вы, возможно, захотите сделать.

Последний пример этого: найдите все объявления переменных с именем типа, которое начинается с «Int», но может заканчиваться чем-нибудь еще, например, «Integer» или"IntFractal" и т.д .:

\variables(simpleType(simpleName(/^Int/)), names)
...