parser
— Доступ к распарсенным деревьям Python¶
Модуль parser
предоставляет интерфейс для внутреннего парсера Python и компилятора байт-кода. Основная цель этого интерфейса - позволить коду на Python редактировать дерево выражений Python и создавать из него выполняемый код. Это лучше чем пытаться разобрать и модифицировать произвольный фрагмент кода на Python because parsing is performed in a manner identical to
the code forming the application. Кроме того, это быстрее.
Note
Начиная с 2.5, более удобно влезть в этапы генерации Abstract
Syntax Tree (AST) и компиляции, при помощи подуля ast
.
Модуль parser
экспортирует имена, документированные тут, заменяя “st”
на “ast”; это наследие ещё тех времён, когда не было другого
AST и никак не связано с AST из Python 2.5. Кроме того, это ещё и причина того, что именованные аргументы функций называются ast, а не st.
Функции “ast” убраны в Python 3.
Есть несколько вещей, которые надо иметь ввиду при работе с этим модулем. Данная документация
не является руководством по редактированию распарсенного дерева кода Python, но некоторые примеры
использования модуля parser
Вы тут встретите.
Особенно важно хорошее понимание обработки грамматики Python внутренним парсером. Более подробная
информация о синтаксисе языка находится в The Python Language Reference. Сам парсер создаётся из грамматических
спецификаций, определённых в файле Grammar/Grammar
в стандартной постановке Python. Распарсенные деревья
сохранённые в объектах ST, создаваемых этим модулем, являются актуальным выводом внутреннего парсера,
когда они создаются функциями expr()
или suite()
, описанными ниже. Объекты ST создаваемые
функцией sequence2st()
имеют схожую структуру. Имейте ввиду, что значения последовательностей,
которые “корректны” могут отличаться для разных версий Python, если отличается формальная грамматика языка.
Однако, перенос кода из одной версии Python в другую всегда будет создавать корректное распарсенное
дерево для данной версии, с тем лишь ограничением, что переход на более старую
версию не будет поддерживать более новые конструкции языка. Распарсенные
деревья, обычно, не совместимы меду разными версиями, тогда как для
исходного кода гарантируется forward-compatible.
Каждый элемент последовательности, возвращаемый функциями st2list()
или st2tuple()
имеет простую форму. Последоватльность, представляющая нетерминальные элементы грамматики
всегда имеет длину больше одного. Первый элементом является число, которое идентифицирует
выражение грамматики. Эти числа имеют символические имена, определённые в заголовочном файле
C Include/graminit.h
и в модуле Python symbol
. Каждый дополнительные
элемент последовательности представляет компонент выражения, который был распознан
в исходной строке: они всегда являются последовательносями той же формы, что и родительская
последовательность. Важный аспект этой структуры, который надо иметь ввиду, что ключевые слова,
используемые для идентификации типа родительского узла, такое как if
в
if_stmt
, включается в узел дерева без дополнительной трактовки. Например, ключевое
слово if
представляется кортежем (1, 'if')
, где 1
- числовое значение,
ассоциированное с токеном NAME
, который также включает переменные и функции,
определённые пользователем. В альтернативной возвращаемой форме, когда требуется информация
о номере строки, тот же самый токен может быть представлен как (1, 'if', 12)
, где
12
- номер строки, в которой был найден терминальный символ.
Терминальные элементы представляются похожим образом, но без дочерних элементов и без
дополнений в виде исходного кода, который был идентифицирован. Опять же смотрите выше пример
для ключевого слова if
. Различные типы терминальных символов определены в заголовочном
файле C Include/token.h
и модуле Python token
.
Объекты ST не требуются для поддержки функциональности этого модуля, но они используются для трёх целей: чтобы позволить приложению снизить стоимость обработки сложных распарсенных деревьев, чтобы предоставить представление распарсенного дерева, которое потребляет меньше памяти, чем представление при помощи списков или кортежей, и для того, чтобы проще сождавать дополнительные модули на С, которые манипулируют этими деревьями. Простой класс обёртка может быть создан в Python для того, чтобы скрыть использование объектов ST.
Модель parser
определяет функции для нескольких различных целей. Наиболее важная цель -
создание ST объектов и предобразования этих объектов в другие представления, такие как
распарсенные деревья и компилированные объекты кода, однако есть ещё и функции, которые
служат для запросов типа дерева, представленного объектом ST.
See also
Создание объектов ST¶
Объекты ST могут быть созданы из исходного кода или из распарсенного дерева.
Когда объект ST создаётся из исходного кода, то для создания форм 'eval'
и 'exec'
используются различные функции.
-
parser.
expr
(source)¶ Функция
expr()
парсит параметр source, как если бы это был ввод дляcompile(source, 'file.py', 'eval')
. Если парсинг проходит успешно, то создаётся ST объект, котрый содержит внутреннее представление распарсенного дерева; в противном случае вызывается соответствующее исключение.
-
parser.
suite
(source)¶ Фукция
suite()
парсит параметр source, как если бы это был ввод дляcompile(source, 'file.py', 'exec')
. Если парсинг проходит успешно, то создаётся ST объект, котрый содержит внутреннее представление распарсенного дерева; в противном случае вызывается соответствующее исключение.
-
parser.
sequence2st
(sequence)¶ Эта функция принимает представление распарсенного дерева в качестве последовательности и создаёт внутреннее представление, если это возможно. Если можно проверить, что дерево соответствует грамматике Python и все узлы являются корректным типом узлов в данной версии Pythonб то из внутреннего представления создаётся объект ST и он возвращается функцией. Если возникает проблема с созданием внутреннего представления или дерево не может быть проверено, вызывается исключение
ParserError
. Объект ST, создаваемый таким образом, не обязательно будет корректно компилироваться; обычные исключения, которые возникают при компиляции всё ещё могут возникать, когда ST объект передаётся вcompilest()
. Это может означать наличие проблем, которые не связаны с синтакисом (такие как исключениеMemoryError
), но могут быть вызваны конструкциями типаdel f(0)
, которые проходят парсер Python, но при этом проверяются компилятором байт-кода.Последовательности, представляющие терминальные токены, могут быть представлены либо как двух-элементный список формы
(1, 'name')
или трёх-элементный спискок вида(1, 'name', 56)
. Если есть третий элемент, то это должен быть корректный номер строки. Номер строки может быть определён для любого набора терминальных символов во входном дереве.
-
parser.
tuple2st
(sequence)¶ Та же самая функция, что и
sequence2st()
. Эта точка входа существует для обеспечения обратной совместимости.
Преобразование объектов ST¶
ST объекты, вне зависимости от исходных данных, на основе которых они созданы, могут быть преобразованы в представление распарсенных деревьев в виде деревьев списков или кортежей, или же могут быть скомпилированы в исполняемые объекты кода. Распарсенные деревья могут быть извлечены с или без информацией о номере строк.
-
parser.
st2list
(ast[, line_info])¶ Эта функция принимает объект ST, полученный вызовом ast и возвращает список Python представляющий аналогичное распарсенное дерево. Результирующий список может быть использован для изучения или создания нового распарсенного дерева в форме списка. Эта функция работает пока есть достаточно памяти для построения спискового представления. Если полученное дерево будет использовано только для изучения, то надо использовать функцию
st2tuple()
для сокращения потребления памяти и уменьшения фрагментации. Когда требуется списковое представление, то эта функция работает гораздо быстрее, чем получение представления в виде кортежа и преобразования его в список.Если line_info=True, то для всех терминальных токенов будет добавлен номер строки в качестве третьего элемента списка. Обратите внимание, что номер строки определяется строкой, на которой токен заканчивается. Эта информация не указывается если флаг установлен в false или вообще не передан.
-
parser.
st2tuple
(ast[, line_info])¶ Эта функция принимает объект ST, полученный вызовом ast и возвращает кортеж Python, представляющий соответсвующее распарсенное дерево. Кроме того, что эта функция возвращает кортеж, а не список, в остальном она идентична функции
st2list()
.Если line_info=True, то для всех терминальных токенов будет добавлен номер строки в качестве третьего элемента спискового представления. Эта информация не указывается если флаг установлен в false или вообще не передан.
-
parser.
compilest
(ast, filename='<syntax-tree>')¶ Компилятор байт-кода Python может быть вызван для объекта ST чтобы создать объект кода, который может быть использован как часть выражения
exec
или быть вызван через функциюeval()
. Эта функция предоставляет интерфейс для компилятора, передавая внутреннее распарсенное дерево из ast в парсер при помощи имени исходного файла, определённого в параметре filename. Значение по умолчанию filename означает, что источником является объект ST.Компиляция объекта ST может привести к исключению, связанному с компиляцией; примером может быть
SyntaxError
, вызванный для выраженияdel f(0)
в дереве: это выражение корректно с точки зрения формальной грамматики Python, но при этом не является корретной конструкцией языка.SyntaxError
, которое будет вызвано в таком случае, генерируется компилятором байт-кода, поэтому оно генерируется в модулеparser
. Большая часть ошибок компиляции может быть обнаружена программным образом при изучении распарсенного дерева.
Запросы к объектам ST¶
Кроме того, есть две функции, которые позволяют приложению определить, был ли ST
объект создан как выражение или как suite. Ни одна из этих функций не может
быть использована для определения того, был этот объект создан из исходного кода
при помощи expr()
или suite()
или из распарсенного дерева при помощи
sequence2st()
.
-
parser.
isexpr
(ast)¶ Когда ast находится в форме
'eval'
, эта функция возвращает true, в противном случае - false. Это полезно, так как объект кода не может быть запрошен об этой информации при помощи встроенных функций. Обратите внимание, что объект кода, создаваемый функциейcompilest()
не может быть запрошен об этом и он идентичен созданному при помощи встроенной функцииcompile()
.
-
parser.
issuite
(ast)¶ Эта функция аналогична
isexpr()
в том, что она сообщает, является ли объект ST представлением формы'exec'
, обычно известным как “suite.” Не стоит предполагать, что эта функция аналогичнаnot isexpr(ast)
, так как дополнительные синтаксические фрагменты могут поддерживаться в будущем.
Исключения и обработка ошибок¶
Модуль parser
определяет единственное исключение, но он может передавать
другие встроенные исключения из других частей Python runtime environment. Смотрите
документацию по каждой функции в поисках информации, какие исключения она может
вызывать.
-
exception
parser.
ParserError
¶ Исключение, которое вызывается при появлении ошибки в модуле
parser
. В основном он вызывается при ошибках валидации, тогда как встроенное исключениеSyntaxError
вызывается во время нормального парсинга. Аргументом исключения является строка, описывающая причину оишбки, или кортеж, содержащий последовательность из распарсенного дерева, переданного вsequence2st()
, которая привела к ошибке и объясняющую строку. Вызовsequence2st()
должен уметь обрабатывать оба типа исключений, тогда как вызовы других функций в модуле должны обрабатывать только строковые значения исключений.
Обратите внимание, что функции compilest()
, expr()
, и suite()
могут
вызывать исключения, которые обычно вызываются при парсинге и компиляции. Это включает
в себя MemoryError
, OverflowError
, SyntaxError
, и SystemError
.
В этих случаях, эти исключения надо трактовать так же как в любом другом случае.
Подробнее это описано в соответствующем разделе документации.
Объекты ST¶
Упорядочивание и сравнение на равенство доступно для объектов ST. Кроме того их можно
обрабатыать модулем pickle
.
-
parser.
STType
¶ Тип объектов, возвращаемых
expr()
,suite()
иsequence2st()
.
ST объекты имеют следующие методы:
-
ST.
compile
([filename])¶ Аналогичен
compilest(st, filename)
.
-
ST.
isexpr
()¶ Аналогичен
isexpr(st)
.
-
ST.
issuite
()¶ Аналогичен
issuite(st)
.
-
ST.
tolist
([line_info])¶ Аналогичен
st2list(st, line_info)
.
-
ST.
totuple
([line_info])¶ Аналогичен
st2tuple(st, line_info)
.
Пример: эмуляция compile()
¶
Так как многие полезные операции могут быть выполнены между парсингом и созданием байт-кода, простейшая операция - не делать ничего. Для этой цели, использование модуля ;mod:parser для создания промежуточной структуры данных эквивалентно следующему коду:
>>> code = compile('a + 5', 'file.py', 'eval')
>>> a = 5
>>> eval(code)
10
Эквивалентрая операция при помощи модуля parser
немного длиннее и позволяет
получить распарсенное дерево в виде объекта ST:
>>> import parser
>>> st = parser.expr('a + 5')
>>> code = st.compile('file.py')
>>> a = 5
>>> eval(code)
10
Приложение, которому нужны и объект ST и объект кода, может “запаковать” этот код в легко доступные функции:
import parser
def load_suite(source_string):
st = parser.suite(source_string)
return st, st.compile()
def load_expression(source_string):
st = parser.expr(source_string)
return st, st.compile()