Source code for opengrammar.parser.transformer
"""
This module contains the MetaSyntaxTransformer class, which is used to
transform the Lark parse tree into a MetaSyntaxAST.
"""
import typing
from functools import reduce
from typing import List, Union
from lark import Discard, Token, Transformer
from lark.visitors import _DiscardType
from opengrammar.parser.meta_syntax import (
LHS,
RHS,
Conjunction,
Disjunction,
MetaSyntaxAST,
NonTerminal,
Operands,
PostfixCapable,
PostfixType,
Rule,
Terminal,
)
[docs]
class MetaSyntaxTransformer(Transformer[Token, MetaSyntaxAST]):
"""
Transforms the Lark parse tree into a MetaSyntaxAST.
"""
[docs]
def WS(self, token: Token) -> _DiscardType:
"""
Discards whitespace.
:param token: A whitespace token.
"""
return Discard
[docs]
def NEWLINE(self, token: Token) -> _DiscardType:
"""
Discards newlines.
:param token: A newline token.
"""
return Discard
[docs]
def SEPARATOR(self, token: Token) -> _DiscardType:
"""
Discards separators.
:param token: A separator token.
"""
return Discard
[docs]
def DISJUNCTION_SYMBOL(self, token: Token) -> _DiscardType:
"""
Discards disjunction symbols.
:param token: A disjunction symbol token.
"""
return Discard
def TERMINAL(self, token: Token) -> Terminal:
return Terminal(symbol=token[1:-1])
def terminal(self, items: List[Terminal]) -> Terminal:
return items[0]
def NON_TERMINAL(self, token: Token) -> NonTerminal:
return NonTerminal(symbol=token)
def ZERO_OR_MORE(self, token: Token) -> str:
return str(token.value)
def ONE_OR_MORE(self, token: Token) -> str:
return str(token.value)
def OPTIONAL(self, token: Token) -> str:
return str(token.value)
def postfix(self, items: List[str]) -> PostfixType:
operator = items[0]
if operator == "*":
return PostfixType.ZERO_OR_MORE
elif operator == "+":
return PostfixType.ONE_OR_MORE
elif operator == "?":
return PostfixType.OPTIONAL
raise SyntaxError("Unknown PostfixType Defined in Grammar")
def non_terminal(
self, items: Union[List[Union[NonTerminal, PostfixType]], List[NonTerminal]]
) -> NonTerminal:
if len(items) > 1:
nt = typing.cast(NonTerminal, items[0])
nt.postfix = typing.cast(PostfixType, items[1])
return nt
else:
nt = typing.cast(NonTerminal, items[0])
return nt
def lhs_bracketed(self, items: List[Operands]) -> Operands:
return items[1:-1][0]
def lhs_left_non_terminal(self, items: List[Operands]) -> Operands:
statements = reversed(items)
return reduce(lambda a, c: Conjunction(c, a), statements)
def lhs_right_non_terminal(self, items: List[Operands]) -> Operands:
statements = reversed(items)
return reduce(lambda a, c: Conjunction(c, a), statements)
def lhs_conjuncts(self, items: List[Operands]) -> Operands:
return items[0]
def lhs_disjuncts(self, items: List[Operands]) -> Operands:
statements = reversed(items)
return reduce(lambda a, c: Disjunction(c, a), statements)
def lhs_expressions(self, items: List[Operands]) -> Operands:
return items[0]
def lhs(self, items: List[Operands]) -> LHS:
rule: Union[NonTerminal, Conjunction, Disjunction] = typing.cast(
Union[NonTerminal, Conjunction, Disjunction], items[0]
)
return LHS(rule=rule)
def rhs_atoms(self, items: List[Operands]) -> Operands:
return items[0]
def rhs_conjuncts(self, items: List[Operands]) -> Operands:
if len(items) > 1:
statements = reversed(items)
return reduce(lambda a, c: Conjunction(c, a), statements)
else:
return items[0]
def rhs_disjuncts(self, items: List[Operands]) -> Operands:
if len(items) > 1:
statements = reversed(items)
return reduce(lambda a, c: Disjunction(c, a), statements)
else:
return items[0]
def rhs_expressions(self, items: List[Operands]) -> Operands:
return items[0]
def rhs_bracketed(
self, items: List[Union[Disjunction, Conjunction, PostfixType]]
) -> PostfixCapable:
atoms: Union[Disjunction, Conjunction] = typing.cast(
Union[Disjunction, Conjunction], items[1:-2][0]
)
pt: PostfixType = typing.cast(PostfixType, items[1:][-1])
atoms.postfix = pt
return atoms
def rhs(self, items: List[Operands]) -> RHS:
return RHS(rule=items[0])
def rule(self, items: List[Union[LHS, RHS]]) -> Rule:
lhs: LHS = typing.cast(LHS, items[0])
rhs: RHS = typing.cast(RHS, items[0])
return Rule(lhs=lhs, rhs=rhs)
def syntax(self, items: List[Rule]) -> MetaSyntaxAST:
for index, item in enumerate(items):
item.number = index + 1
return MetaSyntaxAST(rules=items)