The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 909142bd authored by eckhart's avatar eckhart
Browse files

- type checking errors (mypy) corrected

parent eaa52b6f
...@@ -230,7 +230,7 @@ def raw_compileEBNF(ebnf_src: str, branding="DSL") -> EBNFCompiler: ...@@ -230,7 +230,7 @@ def raw_compileEBNF(ebnf_src: str, branding="DSL") -> EBNFCompiler:
CompilationError if any errors occurred during compilation CompilationError if any errors occurred during compilation
""" """
grammar = get_ebnf_grammar() grammar = get_ebnf_grammar()
compiler = get_ebnf_compiler(branding , ebnf_src) compiler = get_ebnf_compiler(branding, ebnf_src)
transformer = get_ebnf_transformer() transformer = get_ebnf_transformer()
compileDSL(ebnf_src, nil_preprocessor, grammar, transformer, compiler) compileDSL(ebnf_src, nil_preprocessor, grammar, transformer, compiler)
return compiler return compiler
...@@ -295,6 +295,7 @@ def load_compiler_suite(compiler_suite: str) -> \ ...@@ -295,6 +295,7 @@ def load_compiler_suite(compiler_suite: str) -> \
global RX_SECTION_MARKER global RX_SECTION_MARKER
assert isinstance(compiler_suite, str) assert isinstance(compiler_suite, str)
source = load_if_file(compiler_suite) source = load_if_file(compiler_suite)
imports = DHPARSER_IMPORTS
if is_python_code(compiler_suite): if is_python_code(compiler_suite):
try: try:
intro, imports, preprocessor_py, parser_py, ast_py, compiler_py, outro = \ intro, imports, preprocessor_py, parser_py, ast_py, compiler_py, outro = \
......
...@@ -767,7 +767,7 @@ class EBNFCompiler(Compiler): ...@@ -767,7 +767,7 @@ class EBNFCompiler(Compiler):
'and not a %s.') % (prefix, str(arg.parser))) 'and not a %s.') % (prefix, str(arg.parser)))
return str(arg.result) return str(arg.result)
if str(arg) in self.directives['filter']: if str(arg) in self.directives['filter']:
custom_args = ['filter=%s' % self.directives['filter'][str(arg)]] custom_args = ['rfilter=%s' % self.directives['filter'][str(arg)]]
self.variables.add(str(arg)) # cast(str, arg.result) self.variables.add(str(arg)) # cast(str, arg.result)
elif len(node.children) > 2: elif len(node.children) > 2:
......
...@@ -58,7 +58,7 @@ https://epsil.github.io/gll/ ...@@ -58,7 +58,7 @@ https://epsil.github.io/gll/
import copy import copy
import os import os
from functools import partial from functools import partial
from typing import Any, Callable, cast, Dict, List, Set, Tuple, Union from typing import Any, Callable, cast, Dict, List, Set, Tuple, Union, Optional
from DHParser.error import Error, is_error, has_errors, linebreaks, line_col from DHParser.error import Error, is_error, has_errors, linebreaks, line_col
from DHParser.stringview import StringView, EMPTY_STRING_VIEW from DHParser.stringview import StringView, EMPTY_STRING_VIEW
...@@ -219,10 +219,10 @@ class HistoryRecord: ...@@ -219,10 +219,10 @@ class HistoryRecord:
def add_parser_guard(parser_func): def add_parser_guard(parser_func):
""" """
Add a wrapper function to a parser functions (i.e. Parser.__call__ method) Add a wrapper function to a parser functions (i.e. Parser.__call__ method)
that takes care of memoizing, left recursion and optionally tracing that takes care of memoizing, left recursion and, optionally, tracing
(aka "history tracking") of parser calls. Returns the wrapped call. (aka "history tracking") of parser calls. Returns the wrapped call.
""" """
def guarded_call(parser: 'Parser', text: StringView) -> Tuple[Node, StringView]: def guarded_call(parser: 'Parser', text: StringView) -> Tuple[Optional[Node], StringView]:
try: try:
location = len(text) # mind that location is always the distance to the end location = len(text) # mind that location is always the distance to the end
grammar = parser.grammar # grammar may be 'None' for unconnected parsers! grammar = parser.grammar # grammar may be 'None' for unconnected parsers!
...@@ -330,7 +330,7 @@ class Parser(ParserBase): ...@@ -330,7 +330,7 @@ class Parser(ParserBase):
can for example be returned by the `ZeroOrMore`-parser in case the can for example be returned by the `ZeroOrMore`-parser in case the
contained parser is repeated zero times. contained parser is repeated zero times.
Attributes: Attributes and Properties:
visited: Mapping of places this parser has already been to visited: Mapping of places this parser has already been to
during the current parsing process onto the results the during the current parsing process onto the results the
parser returned at the respective place. This dictionary parser returned at the respective place. This dictionary
...@@ -381,12 +381,11 @@ class Parser(ParserBase): ...@@ -381,12 +381,11 @@ class Parser(ParserBase):
"""Initializes or resets any parser variables. If overwritten, """Initializes or resets any parser variables. If overwritten,
the `reset()`-method of the parent class must be called from the the `reset()`-method of the parent class must be called from the
`reset()`-method of the derived class.""" `reset()`-method of the derived class."""
self.visited = dict() # type: Dict[int, Tuple[Node, StringView]] self.visited = dict() # type: Dict[int, Tuple[Optional[Node], StringView]]
self.recursion_counter = dict() # type: Dict[int, int] self.recursion_counter = dict() # type: Dict[int, int]
self.cycle_detection = set() # type: Set[Callable] self.cycle_detection = set() # type: Set[Callable]
return self
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
"""Applies the parser to the given `text` and returns a node with """Applies the parser to the given `text` and returns a node with
the results or None as well as the text at the position right behind the results or None as well as the text at the position right behind
the matching string.""" the matching string."""
...@@ -421,7 +420,7 @@ class Parser(ParserBase): ...@@ -421,7 +420,7 @@ class Parser(ParserBase):
assigned to a grammar.""" assigned to a grammar."""
pass pass
def apply(self, func: ApplyFunc): def apply(self, func: ApplyFunc) -> bool:
""" """
Applies function `func(parser)` recursively to this parser and all Applies function `func(parser)` recursively to this parser and all
descendant parsers if any exist. The same function can never descendant parsers if any exist. The same function can never
...@@ -628,7 +627,7 @@ class Grammar: ...@@ -628,7 +627,7 @@ class Grammar:
If turned off, a recursion error will result in case of left If turned off, a recursion error will result in case of left
recursion. recursion.
""" """
root__ = None # type: Union[Parser, None] root__ = ZOMBIE_PARSER # type: ParserBase
# root__ must be overwritten with the root-parser by grammar subclass # root__ must be overwritten with the root-parser by grammar subclass
parser_initialization__ = "pending" # type: str parser_initialization__ = "pending" # type: str
# some default values # some default values
...@@ -668,10 +667,11 @@ class Grammar: ...@@ -668,10 +667,11 @@ class Grammar:
if isinstance(parser, Parser) and sane_parser_name(entry): if isinstance(parser, Parser) and sane_parser_name(entry):
if not parser.name: if not parser.name:
parser._name = entry parser._name = entry
if (isinstance(parser, Forward) and (not parser.parser._name)): if isinstance(parser, Forward) and (not parser.parser._name):
parser.parser._name = entry parser.parser._name = entry
cls.parser_initialization__ = "done" cls.parser_initialization__ = "done"
def __init__(self, root: Parser=None) -> None: def __init__(self, root: Parser=None) -> None:
# if not hasattr(self.__class__, 'parser_initialization__'): # if not hasattr(self.__class__, 'parser_initialization__'):
# self.__class__.parser_initialization__ = "pending" # self.__class__.parser_initialization__ = "pending"
...@@ -679,7 +679,7 @@ class Grammar: ...@@ -679,7 +679,7 @@ class Grammar:
# self.wspL__ = '' # self.wspL__ = ''
# if not hasattr(self.__class__, 'wspR__'): # if not hasattr(self.__class__, 'wspR__'):
# self.wspR__ = '' # self.wspR__ = ''
self.all_parsers__ = set() # type: Set[Parser] self.all_parsers__ = set() # type: Set[ParserBase]
self._dirty_flag__ = False # type: bool self._dirty_flag__ = False # type: bool
self.history_tracking__ = False # type: bool self.history_tracking__ = False # type: bool
self.memoization__ = True # type: bool self.memoization__ = True # type: bool
...@@ -792,6 +792,7 @@ class Grammar: ...@@ -792,6 +792,7 @@ class Grammar:
parser = self[start_parser] if isinstance(start_parser, str) else start_parser parser = self[start_parser] if isinstance(start_parser, str) else start_parser
assert parser.grammar == self, "Cannot run parsers from a different grammar object!" \ assert parser.grammar == self, "Cannot run parsers from a different grammar object!" \
" %s vs. %s" % (str(self), str(parser.grammar)) " %s vs. %s" % (str(self), str(parser.grammar))
result = None # type: Optional[Node]
stitches = [] # type: List[Node] stitches = [] # type: List[Node]
rest = self.document__ rest = self.document__
if not rest: if not rest:
...@@ -837,6 +838,7 @@ class Grammar: ...@@ -837,6 +838,7 @@ class Grammar:
if any(self.variables__.values()): if any(self.variables__.values()):
error_str = "Capture-retrieve-stack not empty after end of parsing: " + \ error_str = "Capture-retrieve-stack not empty after end of parsing: " + \
str(self.variables__) str(self.variables__)
if result:
if result.children: if result.children:
# add another child node at the end to ensure that the position # add another child node at the end to ensure that the position
# of the error will be the end of the text. Otherwise, the error # of the error will be the end of the text. Otherwise, the error
...@@ -989,7 +991,7 @@ class PreprocessorToken(Parser): ...@@ -989,7 +991,7 @@ class PreprocessorToken(Parser):
assert RX_PREPROCESSOR_TOKEN.match(token) assert RX_PREPROCESSOR_TOKEN.match(token)
super(PreprocessorToken, self).__init__(token) super(PreprocessorToken, self).__init__(token)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
if text[0:1] == BEGIN_TOKEN: if text[0:1] == BEGIN_TOKEN:
end = text.find(END_TOKEN, 1) end = text.find(END_TOKEN, 1)
if end < 0: if end < 0:
...@@ -1044,8 +1046,9 @@ class RegExp(Parser): ...@@ -1044,8 +1046,9 @@ class RegExp(Parser):
regexp = self.regexp.pattern regexp = self.regexp.pattern
return RegExp(regexp, self.name) return RegExp(regexp, self.name)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
match = text[0:1] != BEGIN_TOKEN and text.match(self.regexp) # ESC starts a preprocessor token. if text[0:1] != BEGIN_TOKEN: # ESC starts a preprocessor token.
match = text.match(self.regexp)
if match: if match:
end = text.index(match.end()) end = text.index(match.end())
return Node(self, text[:end]), text[end:] return Node(self, text[:end]), text[end:]
...@@ -1118,7 +1121,7 @@ class RE(Parser): ...@@ -1118,7 +1121,7 @@ class RE(Parser):
regexp = self.main.regexp.pattern regexp = self.main.regexp.pattern
return self.__class__(regexp, self.wL, self.wR, self.name) return self.__class__(regexp, self.wL, self.wR, self.name)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
# assert self.main.regexp.pattern != "@" # assert self.main.regexp.pattern != "@"
t = text # type: StringView t = text # type: StringView
wL, t = self.wspLeft(t) wL, t = self.wspLeft(t)
...@@ -1143,13 +1146,15 @@ class RE(Parser): ...@@ -1143,13 +1146,15 @@ class RE(Parser):
if self.wR is None: if self.wR is None:
self.wspRight = self.grammar.wsp_right_parser__ self.wspRight = self.grammar.wsp_right_parser__
def apply(self, func: Parser.ApplyFunc): def apply(self, func: Parser.ApplyFunc) -> bool:
if super(RE, self).apply(func): if super(RE, self).apply(func):
if self.wL: if self.wL:
self.wspLeft.apply(func) self.wspLeft.apply(func)
if self.wR: if self.wR:
self.wspRight.apply(func) self.wspRight.apply(func)
self.main.apply(func) self.main.apply(func)
return True
return False
class Token(RE): class Token(RE):
...@@ -1202,9 +1207,11 @@ class UnaryOperator(Parser): ...@@ -1202,9 +1207,11 @@ class UnaryOperator(Parser):
parser = copy.deepcopy(self.parser, memo) parser = copy.deepcopy(self.parser, memo)
return self.__class__(parser, self.name) return self.__class__(parser, self.name)
def apply(self, func: Parser.ApplyFunc): def apply(self, func: Parser.ApplyFunc) -> bool:
if super(UnaryOperator, self).apply(func): if super(UnaryOperator, self).apply(func):
self.parser.apply(func) self.parser.apply(func)
return True
return False
class NaryOperator(Parser): class NaryOperator(Parser):
...@@ -1227,10 +1234,12 @@ class NaryOperator(Parser): ...@@ -1227,10 +1234,12 @@ class NaryOperator(Parser):
parsers = copy.deepcopy(self.parsers, memo) parsers = copy.deepcopy(self.parsers, memo)
return self.__class__(*parsers, name=self.name) return self.__class__(*parsers, name=self.name)
def apply(self, func: Parser.ApplyFunc): def apply(self, func: Parser.ApplyFunc) -> bool:
if super(NaryOperator, self).apply(func): if super(NaryOperator, self).apply(func):
for parser in self.parsers: for parser in self.parsers:
parser.apply(func) parser.apply(func)
return True
return False
class Option(UnaryOperator): class Option(UnaryOperator):
...@@ -1268,7 +1277,7 @@ class Option(UnaryOperator): ...@@ -1268,7 +1277,7 @@ class Option(UnaryOperator):
# "Nesting options with required elements is contradictory: " \ # "Nesting options with required elements is contradictory: " \
# "%s(%s)" % (str(name), str(parser.name)) # "%s(%s)" % (str(name), str(parser.name))
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
node, text = self.parser(text) node, text = self.parser(text)
if node: if node:
return Node(self, node), text return Node(self, node), text
...@@ -1295,7 +1304,7 @@ class ZeroOrMore(Option): ...@@ -1295,7 +1304,7 @@ class ZeroOrMore(Option):
EBNF-Notation: `{ ... }` EBNF-Notation: `{ ... }`
EBNF-Example: `sentence = { /\w+,?/ } "."` EBNF-Example: `sentence = { /\w+,?/ } "."`
""" """
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
results = () # type: Tuple[Node, ...] results = () # type: Tuple[Node, ...]
n = len(text) + 1 n = len(text) + 1
while text and len(text) < n: while text and len(text) < n:
...@@ -1336,7 +1345,7 @@ class OneOrMore(UnaryOperator): ...@@ -1336,7 +1345,7 @@ class OneOrMore(UnaryOperator):
"Use ZeroOrMore instead of nesting OneOrMore and Option: " \ "Use ZeroOrMore instead of nesting OneOrMore and Option: " \
"%s(%s)" % (str(name), str(parser.name)) "%s(%s)" % (str(name), str(parser.name))
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
results = () # type: Tuple[Node, ...] results = () # type: Tuple[Node, ...]
text_ = text # type: StringView text_ = text # type: StringView
n = len(text) + 1 n = len(text) + 1
...@@ -1378,8 +1387,8 @@ class Series(NaryOperator): ...@@ -1378,8 +1387,8 @@ class Series(NaryOperator):
def __init__(self, *parsers: Parser, mandatory: int = NOPE, name: str = '') -> None: def __init__(self, *parsers: Parser, mandatory: int = NOPE, name: str = '') -> None:
super(Series, self).__init__(*parsers, name=name) super(Series, self).__init__(*parsers, name=name)
L = len(self.parsers) L = len(self.parsers)
assert 1 <= L < Series.NOPE, 'Length %i of series exceeds maximum length of %i' \ assert 1 <= L < Series.NOPE, ('Length %i of series exceeds maximum length of %i'
% (L, Series.NOPE) % (L, Series.NOPE))
if mandatory < 0: mandatory += L if mandatory < 0: mandatory += L
assert 0 <= mandatory < L or mandatory == Series.NOPE assert 0 <= mandatory < L or mandatory == Series.NOPE
self.mandatory = mandatory self.mandatory = mandatory
...@@ -1388,7 +1397,7 @@ class Series(NaryOperator): ...@@ -1388,7 +1397,7 @@ class Series(NaryOperator):
parsers = copy.deepcopy(self.parsers, memo) parsers = copy.deepcopy(self.parsers, memo)
return self.__class__(*parsers, mandatory=self.mandatory, name=self.name) return self.__class__(*parsers, mandatory=self.mandatory, name=self.name)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
results = () # type: Tuple[Node, ...] results = () # type: Tuple[Node, ...]
text_ = text # type: StringView text_ = text # type: StringView
pos = 0 pos = 0
...@@ -1421,7 +1430,7 @@ class Series(NaryOperator): ...@@ -1421,7 +1430,7 @@ class Series(NaryOperator):
# `RE('\d+') + Optional(RE('\.\d+)` instead of `Series(RE('\d+'), Optional(RE('\.\d+))` # `RE('\d+') + Optional(RE('\.\d+)` instead of `Series(RE('\d+'), Optional(RE('\.\d+))`
@staticmethod @staticmethod
def combined_mandatory(left, right): def combined_mandatory(left: Parser, right: Parser):
left_mandatory, left_length = (left.mandatory, len(left.parsers)) \ left_mandatory, left_length = (left.mandatory, len(left.parsers)) \
if isinstance(left, Series) else (Series.NOPE, 1) if isinstance(left, Series) else (Series.NOPE, 1)
if left_mandatory != Series.NOPE: if left_mandatory != Series.NOPE:
...@@ -1480,7 +1489,7 @@ class Alternative(NaryOperator): ...@@ -1480,7 +1489,7 @@ class Alternative(NaryOperator):
assert all(not isinstance(p, Option) for p in self.parsers[:-1]), \ assert all(not isinstance(p, Option) for p in self.parsers[:-1]), \
"Parser-specification Error: only the last alternative may be optional!" "Parser-specification Error: only the last alternative may be optional!"
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
for parser in self.parsers: for parser in self.parsers:
node, text_ = parser(text) node, text_ = parser(text)
if node: if node:
...@@ -1531,19 +1540,18 @@ class AllOf(NaryOperator): ...@@ -1531,19 +1540,18 @@ class AllOf(NaryOperator):
EBNF-Notation: `<... ...>` (sequence of parsers enclosed by angular brackets) EBNF-Notation: `<... ...>` (sequence of parsers enclosed by angular brackets)
EBNF-Example: `set = <letter letter_or_digit>` EBNF-Example: `set = <letter letter_or_digit>`
""" """
def __init__(self, *parsers: Parser, name: str = '') -> None: def __init__(self, *parsers: Parser, name: str = '') -> None:
if len(parsers) == 1: if len(parsers) == 1 and isinstance(parsers[0], Series):
assert isinstance(parsers[0], Series), \ assert isinstance(parsers[0], Series), \
"Parser-specification Error: No single arguments other than a Series " \ "Parser-specification Error: No single arguments other than a Series " \
"allowed as arguments for AllOf-Parser !" "allowed as arguments for AllOf-Parser !"
assert parsers[0].mandatory == Series.NOPE, \ series = cast(Series, parsers[0])
assert series.mandatory == Series.NOPE, \
"AllOf cannot contain mandatory (§) elements!" "AllOf cannot contain mandatory (§) elements!"
parsers = parsers[0].parsers parsers = series.parsers
super().__init__(*parsers, name=name) super().__init__(*parsers, name=name)
def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
def __call__(self, text: StringView) -> Tuple[Node, StringView]:
results = () # type: Tuple[Node, ...] results = () # type: Tuple[Node, ...]
text_ = text # type: StringView text_ = text # type: StringView
parsers = list(self.parsers) # type: List[Parser] parsers = list(self.parsers) # type: List[Parser]
...@@ -1582,16 +1590,16 @@ class SomeOf(NaryOperator): ...@@ -1582,16 +1590,16 @@ class SomeOf(NaryOperator):
EBNF-Notation: `<... ...>` (sequence of parsers enclosed by angular brackets) EBNF-Notation: `<... ...>` (sequence of parsers enclosed by angular brackets)
EBNF-Example: `set = <letter letter_or_digit>` EBNF-Example: `set = <letter letter_or_digit>`
""" """
def __init__(self, *parsers: Parser, name: str = '') -> None: def __init__(self, *parsers: Parser, name: str = '') -> None:
if len(parsers) == 1: if len(parsers) == 1:
assert isinstance(parsers[0], Alternative), \ assert isinstance(parsers[0], Alternative), \
"Parser-specification Error: No single arguments other than a Alternative " \ "Parser-specification Error: No single arguments other than a Alternative " \
"allowed as arguments for SomeOf-Parser !" "allowed as arguments for SomeOf-Parser !"
parsers = parsers[0].parsers alternative = cast(Alternative, parsers[0])
parsers = alternative.parsers
super().__init__(*parsers, name=name) super().__init__(*parsers, name=name)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
results = () # type: Tuple[Node, ...] results = () # type: Tuple[Node, ...]
text_ = text # type: StringView text_ = text # type: StringView
parsers = list(self.parsers) # type: List[Parser] parsers = list(self.parsers) # type: List[Parser]
...@@ -1644,7 +1652,7 @@ class FlowOperator(UnaryOperator): ...@@ -1644,7 +1652,7 @@ class FlowOperator(UnaryOperator):
# """ # """
# RX_ARGUMENT = re.compile(r'\s(\S)') # RX_ARGUMENT = re.compile(r'\s(\S)')
# #
# def __call__(self, text: StringView) -> Tuple[Node, StringView]: # def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
# node, text_ = self.parser(text) # node, text_ = self.parser(text)
# if not node: # if not node:
# m = text.search(Required.RX_ARGUMENT) # re.search(r'\s(\S)', text) # m = text.search(Required.RX_ARGUMENT) # re.search(r'\s(\S)', text)
...@@ -1663,7 +1671,7 @@ class Lookahead(FlowOperator): ...@@ -1663,7 +1671,7 @@ class Lookahead(FlowOperator):
def __init__(self, parser: Parser, name: str = '') -> None: def __init__(self, parser: Parser, name: str = '') -> None:
super(Lookahead, self).__init__(parser, name) super(Lookahead, self).__init__(parser, name)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
node, text_ = self.parser(text) node, text_ = self.parser(text)
if self.sign(node is not None): if self.sign(node is not None):
return Node(self, ''), text return Node(self, ''), text
...@@ -1695,7 +1703,7 @@ class Lookbehind(FlowOperator): ...@@ -1695,7 +1703,7 @@ class Lookbehind(FlowOperator):
self.regexp = cast(RE, p).main.regexp if isinstance(p, RE) else p.regexp self.regexp = cast(RE, p).main.regexp if isinstance(p, RE) else p.regexp
super(Lookbehind, self).__init__(parser, name) super(Lookbehind, self).__init__(parser, name)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
backwards_text = self.grammar.reversed__[len(text):] # self.grammar.document__[-len(text) - 1::-1] backwards_text = self.grammar.reversed__[len(text):] # self.grammar.document__[-len(text) - 1::-1]
if self.sign(backwards_text.match(self.regexp)): if self.sign(backwards_text.match(self.regexp)):
return Node(self, ''), text return Node(self, ''), text
...@@ -1731,7 +1739,7 @@ class Capture(UnaryOperator): ...@@ -1731,7 +1739,7 @@ class Capture(UnaryOperator):
def __init__(self, parser: Parser, name: str = '') -> None: def __init__(self, parser: Parser, name: str = '') -> None:
super(Capture, self).__init__(parser, name) super(Capture, self).__init__(parser, name)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
node, text_ = self.parser(text) node, text_ = self.parser(text)
if node: if node:
stack = self.grammar.variables__.setdefault(self.name, []) stack = self.grammar.variables__.setdefault(self.name, [])
...@@ -1765,26 +1773,26 @@ def accumulate(stack: List[str]) -> str: ...@@ -1765,26 +1773,26 @@ def accumulate(stack: List[str]) -> str:
class Retrieve(Parser): class Retrieve(Parser):
"""STILL EXPERIMENTAL!""" """STILL EXPERIMENTAL!"""
def __init__(self, symbol: Parser, filter: RetrieveFilter = None, name: str = '') -> None: def __init__(self, symbol: Parser, rfilter: RetrieveFilter = None, name: str = '') -> None:
super(Retrieve, self).__init__(name) super(Retrieve, self).__init__(name)
self.symbol = symbol self.symbol = symbol
self.filter = filter if filter else last_value self.filter = rfilter if rfilter else last_value
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
return self.__class__(self.symbol, self.filter, self.name) return self.__class__(self.symbol, self.filter, self.name)
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
return self.call(text) # allow call method to be called from subclass circumventing the parser guard return self.call(text) # allow call method to be called from subclass circumventing the parser guard
def __repr__(self): def __repr__(self):
return ':' + self.symbol.repr return ':' + self.symbol.repr
def call(self, text: StringView) -> Tuple[Node, StringView]: def call(self, text: StringView) -> Tuple[Optional[Node], StringView]:
try: try:
stack = self.grammar.variables__[self.symbol.name] stack = self.grammar.variables__[self.symbol.name]
value = self.filter(stack) value = self.filter(stack)
except (KeyError, IndexError): except (KeyError, IndexError):
return Node(self, '').add_error(dsl_error_msg(self, \ return Node(self, '').add_error(dsl_error_msg(self,
"'%s' undefined or exhausted." % self.symbol.name)), text "'%s' undefined or exhausted." % self.symbol.name)), text
if text.startswith(value): if text.startswith(value):
return Node(self, value), text[len(value):] return Node(self, value), text[len(value):]
...@@ -1795,7 +1803,7 @@ class Retrieve(Parser): ...@@ -1795,7 +1803,7 @@ class Retrieve(Parser):
class Pop(Retrieve): class Pop(Retrieve):
"""STILL EXPERIMENTAL!!!""" """STILL EXPERIMENTAL!!!"""
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
nd, txt = super(Pop, self).call(text) # call() instead of __call__() to avoid parser guard nd, txt = super(Pop, self).call(text) # call() instead of __call__() to avoid parser guard
if nd and not nd.error_flag: if nd and not nd.error_flag:
stack = self.grammar.variables__[self.symbol.name] stack = self.grammar.variables__[self.symbol.name]
...@@ -1827,7 +1835,7 @@ class Synonym(UnaryOperator): ...@@ -1827,7 +1835,7 @@ class Synonym(UnaryOperator):
class, in which case it would be unclear whether the parser class, in which case it would be unclear whether the parser
RE('\d\d\d\d') carries the name 'JAHRESZAHL' or 'jahr'. RE('\d\d\d\d') carries the name 'JAHRESZAHL' or 'jahr'.
""" """
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
node, text = self.parser(text) node, text = self.parser(text)
if node: if node:
return Node(self, node), text return Node(self, node), text
...@@ -1867,7 +1875,7 @@ class Forward(Parser): ...@@ -1867,7 +1875,7 @@ class Forward(Parser):
duplicate.set(parser) duplicate.set(parser)
return duplicate return duplicate
def __call__(self, text: StringView) -> Tuple[Node, StringView]: def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
return self.parser(text) return self.parser(text)