Подумав об этом несколько дней назад и не придумав ничего стоящего, я вернулся к нему сейчас и придумал какой-то синтаксис, который мне скорее нравится, потому что он почти похож на python:
macro PrintMacro:
syntax:
"print", OneOrMore(Var(), name='vars')
return Printnl(vars, None)
- Сделать все макросы "ключевые слова" похожими на создание объектов Python (
Var()
вместо простых Var
)
Передать имя элемента в качестве «параметра ключевого слова» элементам, для которых мы хотим получить имя.
Все равно должно быть легко найти все имена в синтаксическом анализаторе, так как это определение синтаксиса в любом случае необходимо интерпретировать каким-либо образом, чтобы заполнить синтаксическую переменную классов макросов.
необходимо преобразовать, чтобы заполнить синтаксическую переменную результирующего макрокласса.
Внутреннее синтаксическое представление также может выглядеть так же:
class PrintMacro(Macro):
syntax = 'print', OneOrMore(Var(), name='vars')
...
Внутренние синтаксические классы, такие как OneOrMore
, будут следовать этому шаблону, чтобы разрешить подэлементы и необязательное имя:
class MacroSyntaxElement(object):
def __init__(self, *p, name=None):
self.subelements = p
self.name = name
Когда макрос совпадает, вы просто собираете все элементы с именами и передаете их в качестве параметров ключевых слов в функцию-обработчик:
class Macro():
...
def parse(self, ...):
syntaxtree = []
nameditems = {}
# parse, however this is done
# store all elements that have a name as
# nameditems[name] = parsed_element
self.handle(syntaxtree, **nameditems)
Функция обработчика будет тогда определена так:
class PrintMacro(Macro):
...
def handle(self, syntaxtree, vars):
return Printnl(vars, None)
Я добавил синтаксис в качестве первого параметра, который всегда передается, так что вам не нужно иметь никаких именованных элементов, если вы просто хотите делать очень простые вещи в синтаксическом дереве.
Кроме того, если вам не нравятся декораторы, почему бы не добавить тип макроса как "базовый класс"? IfMacro
будет выглядеть так:
macro IfMacro(MultiLine):
syntax:
Group("if", Var(), ":", Var(), name='if_')
ZeroOrMore("elif", Var(), ":", Var(), name='elifs')
Optional("else", Var(name='elseBody'))
return If(
[(cond, Stmt(body)) for keyword, cond, colon, body in [if_] + elifs],
None if elseBody is None else Stmt(elseBody)
)
А во внутреннем представлении:
class IfMacro(MultiLineMacro):
syntax = (
Group("if", Var(), ":", Var(), name='if_'),
ZeroOrMore("elif", Var(), ":", Var(), name='elifs'),
Optional("else", Var(name='elseBody'))
)
def handle(self, syntaxtree, if_=None, elifs=None, elseBody=None):
# Default parameters in case there is no such named item.
# In this case this can only happen for 'elseBody'.
return If(
[(cond, Stmt(body)) for keyword, cond, body in [if_] + elifs],
None if elseNody is None else Stmt(elseBody)
)
Я думаю, это дало бы довольно гибкую систему. Основные преимущества:
- Легко учиться (выглядит как стандартный питон)
- Легко разбирать (разбирает как стандартный питон)
- Опциональные элементы могут быть легко обработаны, так как в обработчике может быть параметр по умолчанию
None
- Гибкое использование именованных предметов:
- Вам не нужно называть какие-либо элементы, если вы не хотите, потому что дерево синтаксиса всегда передается.
- Вы можете назвать любые подвыражения в большом макроопределении, так что легко выбрать конкретный материал, который вас интересует
- Легко расширяется, если вы хотите добавить больше функций в конструкции макросов. Например
Several("abc", min=3, max=5, name="a")
. Я думаю, что это также может быть использовано для добавления значений по умолчанию для дополнительных элементов, таких как Optional("step", Var(), name="step", default=1)
.
Я не уверен насчет синтаксиса quote / unquote с «quote:» и «$», но для этого необходим некоторый синтаксис, поскольку он значительно упрощает жизнь, если вам не нужно вручную писать деревья синтаксиса. Вероятно, это хорошая идея - требовать (или просто разрешать?) Скобки для «$», чтобы вы могли вставлять более сложные синтаксические части, если хотите. Как $(Stmt(a, b, c))
.
ToMacro будет выглядеть примерно так:
# macro definition
macro ToMacro(Partial):
syntax:
Var(name='start'), "to", Var(name='end'), Optional("inclusive", name='inc'), Optional("step", Var(name='step'))
if step == None:
step = quote(1)
if inclusive:
return quote:
xrange($(start), $(end)+1, $(step))
else:
return quote:
xrange($(start), $(end), $(step))
# resulting macro class
class ToMacro(PartialMacro):
syntax = Var(name='start'), "to", Var(name='end'), Optional("inclusive", name='inc'), Optional("step", Var(name='step'))
def handle(syntaxtree, start=None, end=None, inc=None, step=None):
if step is None:
step = Number(1)
if inclusive:
return ['xrange', ['(', start, [end, '+', Number(1)], step, ')']]
return ['xrange', ['(', start, end, step, ')']]