libcst: Вставка нового узла добавляет встроенный код и точку с запятой

#python #parsing #concrete-syntax-tree #libcst

Вопрос:

Я пытаюсь ввести новый узел (как новую строку кода), точно перед назначенным узлом.

Проблема возникает при использовании FlattenSentinel для представления нового узла, так как я хочу, чтобы узел был отдельным, но libcst объединяет их с помощью точки с запятой ( ; ), пример:

 a = 6
 

Становится:

 print('returning'); a = 6
 

Код для воспроизведения примера:

 import libcst as cst
class MyTransformer(cst.CSTTransformer):

    def leave_Assign(self, old_node, updated_node):
        log_stmt = cst.Expr(cst.parse_expression("print('returning')"))
        return cst.FlattenSentinel([log_stmt, updated_node])

source_tree = cst.parse_module("a = 6")
modified_tree = source_tree.visit(MyTransformer())
print(modified_tree.code)
 

Я также попытался ввести новую строку, но это выглядит еще хуже, пример кода:

 def leave_Assign(self, old_node, updated_node):
    log_stmt = cst.Expr(cst.parse_expression("print('returning')"))
    return cst.FlattenSentinel([log_stmt, cst.Expr(cst.Newline()), updated_node])
 

Моим желаемым результатом было бы вставить новый узел над существующим узлом (на том же уровне ), без точки с запятой, как это:

 print('returning')
a = 6
 

Возможно ли это в libcst?

Ответ №1:

Твой АСТ такой:

 Module
  FunctionDef
    SimpleStatementLine
      Assign
        Target
        Integer
 

Когда вы пытаетесь заменить назначение несколькими узлами, вам все равно нужно соблюдать текущую строку, которая заставляет точки с запятой.

 Module
  FunctionDef
    SimpleStatementLine
      Call // Your print call
      Assign // a = 6
        Target
        Integer
 

Вместо этого вы хотите заменить родительский SimpleStatementLine FlattenSentinel элемент на новый SimpleStatementLine s с вашими новыми узлами. Таким образом, вам действительно нужно изменить свой код, чтобы работать дальше leave_SimpleStatementLine .