Совпадение корневого элемента частичного AST - PullRequest
1 голос
/ 08 июля 2019

Я хочу провести рефакторинг кода на C, используя Clair и Rascal. Я ищу функцию с определенным именем. Если я найду такую ​​функцию, я хочу заменить ее другой функцией. Мне нужно выбрать между четырьмя функциями. Выбор функции зависит от аргумента найденной функции. Мне нужно сопоставить корневой элемент выражения.

Я могу сопоставить, используя схему посещения. Я пытался

visit(body) {
  case \functionCall(func, args): {
    if ("myName" == func.name.\value) {
      visit(args[0]) {
        case \equals(_, _): println("Equals");
        case \notEquals(_, _): println("Not equals");
      }             
    }
  }
}

Это не гарантирует, что я соответствую корневому элементу. В (A! = B) == C я хочу соответствовать только ==

Как мне сопоставить только корневой элемент?

Ответы [ 2 ]

1 голос
/ 08 июля 2019

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

Например:

case functionCall(someId("my name", [e:\equals(_, _), *_]) => newFunctionCall(e)
case functionCall(someId("my name", [e:\notEquals(_, _), *_]) => newFunctionCall(e)

Обратите внимание на шаблон списка [..], который соответствует спискам аргументов произвольной длины, если первый аргумент является выражением равно или не равно.

Таким образом, вы можете повторить регистр верхнего уровня для каждого регистра первого параметра, как указано выше, или вставить переключатель и использовать «insert», как показано ниже:

  case functionCall(someId("my name", [arg, *_]) : 
               switch(arg) {
                  case equals(_, _) : insert newFunctionCall(arg);
                  ...
               }

Я предпочитаюпервый случай, потому что это более декларативно.Мошенник должен учитывать общие вещи для эффективности ради внутри страны.Тот факт, что оба шаблона очень похожи, не является запахом кода в Rascal IMHO, потому что в этом весь смысл этого кода, вы хотите обрабатывать два похожих шаблона немного по-разному, и первый пример документа явно, без вложенности потока управления.Другими словами: вкладывать шаблон проще, чем поток управления ?

0 голосов
/ 12 июля 2019

Я использую это поле, потому что в поле комментария ограничено пространство.

Мне нравится эта особенность вложенных шаблонов, но я не могу сопоставить простой случай.Я попробовал следующие шаблоны:

    visit(body) {
        case \functionCall("methodA", [arg, *_]): println("match");
        case \functionCall(SomeId("methodA", [arg, *_])): println("match");
        case \functionCall(SomeId("methodA"), [arg, *_]): println("match");
        case \functionCall(IdExpresssion("methodA", [arg, *_])): println("match");
        case \functionCall(IdExpresssion("methodA"), [arg, *_]): println("match");
        case \functionCall(name("methodA", [arg, *_])): println("match");
        case \functionCall(name("methodA"), [arg, *_]): println("match");
    }

iprint (body) дает следующие результаты:

compoundStatement(
  [
    compoundStatement(
      [
        expressionStatement(
.... some expressions and declarations
        for(
... for statement
          compoundStatement(
            [
... inside for loop
              expressionStatement(
                functionCall(
                  idExpression(
                    name(
                      "methodA",
                      src=|project://Instrumentation/example.c|(11195,10)),
                    src=|project://Instrumentation/example.c|(11195,10),
                    decl=|cpp+problem://Attempt%20to%20use%20symbol%20failed:%20methodA|,
                    typ=problemType("Failure to determine type of expression")),
                  [equals(
                      idExpression(
                        name(
                          "beforeTest",
                          src=|project://Instrumentation/example.c|(11207,20)),
                        src=|project://Instrumentation/example.c|(11207,20),
                        decl=|cpp+variable:///test1()/beforeTest|,
                        typ=problemType("Type depends on an unresolved name")),
                      idExpression(
                        name(
                          "afterTest",
                          src=|project://Instrumentation/example.c|(11231,19)),
                        src=|project://Instrumentation/example.c|(11231,19),
                        decl=|cpp+variable:///test1()/afterTest|,
                        typ=problemType("Type depends on an unresolved name")),
                      src=|project://Instrumentation/example.c|(11207,43),
                      typ=problemType("Type depends on an unresolved name"))],
                  src=|project://Instrumentation/example.c|(11195,57),
                  typ=problemBinding()),
                src=|project://Instrumentation/example.c|(11195,58)),
              expressionStatement(
... more expressions and declaratios in for loop              
  ],
  src=|project://Instrumentation/example.c|(10148,1349))ok

Как создать шаблон, который соответствует MethodA?

...