Commit f60c89e1 authored by eckhart's avatar eckhart

- flake warnings corrected

parent 0bb99a60
......@@ -463,6 +463,7 @@ def compile_on_disk(source_file: str, compiler_suite="", extension=".xml") -> It
compiler1 = cfactory()
compiler1.set_grammar_name(compiler_name, source_file)
result, messages, _ = compile_source(source, sfactory(), pfactory(), tfactory(), compiler1)
if has_errors(messages):
return messages
......@@ -487,8 +488,8 @@ def compile_on_disk(source_file: str, compiler_suite="", extension=".xml") -> It
intro, imports, preprocessor, _, ast, compiler, outro = '', '', '', '', '', '', ''
except ValueError:
name = '"' + rootname + 'Compiler.py"'
raise ValueError('Could not identify all required sections in ' + name +
'. Please delete or repair ' + name + ' manually!')
raise ValueError('Could not identify all required sections in ' + name
+ '. Please delete or repair ' + name + ' manually!')
finally:
if f:
f.close()
......@@ -516,7 +517,7 @@ def compile_on_disk(source_file: str, compiler_suite="", extension=".xml") -> It
f.write(SECTION_MARKER.format(marker=PREPROCESSOR_SECTION))
f.write(preprocessor)
f.write(SECTION_MARKER.format(marker=PARSER_SECTION))
f.write(result)
f.write(cast(str, result))
f.write(SECTION_MARKER.format(marker=AST_SECTION))
f.write(ast)
f.write(SECTION_MARKER.format(marker=COMPILER_SECTION))
......@@ -559,7 +560,7 @@ def compile_on_disk(source_file: str, compiler_suite="", extension=".xml") -> It
def recompile_grammar(ebnf_filename, force=False,
notify: Callable=lambda: None) -> bool:
notify: Callable = lambda: None) -> bool:
"""
Re-compiles an EBNF-grammar if necessary, that is, if either no
corresponding 'XXXXCompiler.py'-file exists or if that file is
......
......@@ -183,7 +183,7 @@ def grammar_changed(grammar_class, grammar_source: str) -> bool:
# grammar_class = load_compiler_suite(grammar_class)[1]
with open(grammar_class, 'r', encoding='utf8') as f:
pycode = f.read()
m = re.search('class \w*\(Grammar\)', pycode)
m = re.search(r'class \w*\(Grammar\)', pycode)
if m:
m = re.search(' source_hash__ *= *"([a-z0-9]*)"',
pycode[m.span()[1]:])
......@@ -476,13 +476,13 @@ class EBNFCompiler(Compiler):
raise EBNFCompilerError('Compiler has not been run before calling '
'"gen_Compiler_Skeleton()"!')
compiler = ['class ' + self.grammar_name + 'Compiler(Compiler):',
' """Compiler for the abstract-syntax-tree of a ' +
self.grammar_name + ' source file.',
' """Compiler for the abstract-syntax-tree of a '
+ self.grammar_name + ' source file.',
' """', '',
' def __init__(self, grammar_name="' +
self.grammar_name + '", grammar_source=""):',
' super(' + self.grammar_name +
'Compiler, self).__init__(grammar_name, grammar_source)',
' def __init__(self, grammar_name="'
+ self.grammar_name + '", grammar_source=""):',
' super(' + self.grammar_name
+ 'Compiler, self).__init__(grammar_name, grammar_source)',
r" assert re.match('\w+\Z', grammar_name)", '',
' def _reset(self):',
' super()._reset()',
......@@ -542,8 +542,8 @@ class EBNFCompiler(Compiler):
definitions.append((self.WHITESPACE_PARSER_KEYWORD,
'Whitespace(%s)' % self.WHITESPACE_KEYWORD))
definitions.append((self.WHITESPACE_KEYWORD,
("mixin_comment(whitespace=" + self.RAW_WS_KEYWORD +
", comment=" + self.COMMENT_KEYWORD + ")")))
("mixin_comment(whitespace=" + self.RAW_WS_KEYWORD
+ ", comment=" + self.COMMENT_KEYWORD + ")")))
definitions.append((self.RAW_WS_KEYWORD, "r'{whitespace}'".format(**self.directives)))
definitions.append((self.COMMENT_KEYWORD, "r'{comment}'".format(**self.directives)))
......@@ -584,7 +584,7 @@ class EBNFCompiler(Compiler):
for symbol in self.symbols:
if symbol not in defined_symbols:
self.tree.new_error(self.symbols[symbol],
"Missing definition for symbol '%s'" % symbol)
"Missing definition for symbol '%s'" % symbol)
# root_node.error_flag = True
# check for unconnected rules
......@@ -643,7 +643,7 @@ class EBNFCompiler(Compiler):
first = self.rules[rule][0]
if not first.errors:
self.tree.new_error(first, 'First definition of rule "%s" '
'followed by illegal redefinitions.' % rule)
'followed by illegal redefinitions.' % rule)
self.tree.new_error(node, 'A rule "%s" has already been defined earlier.' % rule)
elif rule in EBNFCompiler.RESERVED_SYMBOLS:
self.tree.new_error(node, 'Symbol "%s" is a reserved symbol.' % rule)
......@@ -683,7 +683,8 @@ class EBNFCompiler(Compiler):
prepended by the multiline-flag. Returns the regular expression string.
"""
flags = self.re_flags | {'x'} if rx.find('\n') >= 0 else self.re_flags
if flags: rx = "(?%s)%s" % ("".join(flags), rx)
if flags:
rx = "(?%s)%s" % ("".join(flags), rx)
try:
re.compile(rx)
except Exception as re_error:
......@@ -770,7 +771,7 @@ class EBNFCompiler(Compiler):
return ""
def non_terminal(self, node: Node, parser_class: str, custom_args: List[str]=[]) -> str:
def non_terminal(self, node: Node, parser_class: str, custom_args: List[str] = []) -> str:
"""
Compiles any non-terminal, where `parser_class` indicates the Parser class
name for the particular non-terminal.
......@@ -944,7 +945,7 @@ class EBNFCompiler(Compiler):
else:
parser = '_RE('
if rx[:2] == '~/':
if not 'left' in self.directives['literalws']:
if 'left' not in self.directives['literalws']:
name = ['wL=' + self.WHITESPACE_KEYWORD] + name
rx = rx[1:]
elif 'left' in self.directives['literalws']:
......
......@@ -41,7 +41,7 @@ import bisect
from DHParser.preprocess import SourceMapFunc
from DHParser.stringview import StringView
from DHParser.toolkit import typing
from typing import Iterable, Iterator, Union, Tuple, List, NewType
from typing import Iterable, Iterator, Union, Tuple, List
__all__ = ('ErrorCode',
'Error',
......@@ -200,7 +200,7 @@ def line_col(lbreaks: List[int], pos: int) -> Tuple[int, int]:
def adjust_error_locations(errors: List[Error],
original_text: Union[StringView, str],
source_mapping: SourceMapFunc=lambda i: i) -> List[Error]:
source_mapping: SourceMapFunc = lambda i: i) -> List[Error]:
"""Adds (or adjusts) line and column numbers of error messages in place.
Args:
......
......@@ -206,12 +206,13 @@ class HistoryRecord:
COLGROUP = '<colgroup>\n<col style="width:2%"/><col style="width:2%"/><col ' \
'style="width:75%"/><col style="width:6%"/><col style="width:15%"/>\n</colgroup>'
HEADINGS = ('<tr><th>L</th><th>C</th><th>parser call sequence</th>'
'<th>success</th><th>text matched or failed</th></tr>')
HTML_LEAD_IN = ('<!DOCTYPE html>\n'
'<th>success</th><th>text matched or failed</th></tr>')
HTML_LEAD_IN = (
'<!DOCTYPE html>\n'
'<html>\n<head>\n<meta charset="utf-8"/>\n<style>\n'
'td,th {font-family:monospace; '
'border-right: thin solid grey; border-bottom: thin solid grey}\n'
'td.line, td.column {color:darkgrey}\n' # 'td.stack {}\n'
'td.line, td.column {color:darkgrey}\n' # 'td.stack {}\n'
'td.status {font-weight:bold}\n'
'td.text {color:darkblue}\n'
'table {border-spacing: 0px; border: thin solid darkgrey; width:100%}\n'
......@@ -260,10 +261,10 @@ class HistoryRecord:
if status == self.MATCH:
status = '<span class="match">' + status + '</span>'
i = stack.rfind('-&gt;')
chr = stack[i+12:i+13]
chr = stack[i + 12:i + 13]
while not chr.isidentifier() and i >= 0:
i = stack.rfind('-&gt;', 0, i)
chr = stack[i+12:i+13]
chr = stack[i + 12:i + 13]
if i >= 0:
i += 12
k = stack.find('<', i)
......@@ -424,9 +425,9 @@ def log_parsing_history(grammar, log_file_name: str = '', html: bool = True) ->
full_history = ['<h1>Full parsing history of "%s"</h1>' % log_file_name] # type: List[str]
if len(grammar.history__) > LOG_SIZE_THRESHOLD:
warning =('Sorry, man, %iK history records is just too many! '
'Only looking at the last %iK records.'
% (len(grammar.history__) // 1000, LOG_SIZE_THRESHOLD // 1000))
warning = ('Sorry, man, %iK history records is just too many! '
'Only looking at the last %iK records.'
% (len(grammar.history__) // 1000, LOG_SIZE_THRESHOLD // 1000))
html_warning = '<p><strong>' + warning + '</strong></p>'
full_history.append(html_warning)
......@@ -441,4 +442,3 @@ def log_parsing_history(grammar, log_file_name: str = '', html: bool = True) ->
if len(full_history) > LOG_TAIL_THRESHOLD + 10:
heading = '<h1>Last 500 records of parsing history of "%s"</h1>' % log_file_name + lead_in
write_log([heading] + full_history[-LOG_TAIL_THRESHOLD:], log_file_name + '_full.tail')
......@@ -607,7 +607,7 @@ class Grammar:
self.document_length__ = 0 # type: int
self.document_lbreaks__ = [] # type: List[int]
# variables stored and recalled by Capture and Retrieve parsers
self.variables__ = defaultdict(lambda :[]) # type: DefaultDict[str, List[str]]
self.variables__ = defaultdict(lambda: []) # type: DefaultDict[str, List[str]]
self.rollback__ = [] # type: List[Tuple[int, Callable]]
self.last_rb__loc__ = -1 # type: int
# support for call stack tracing
......@@ -666,7 +666,7 @@ class Grammar:
Node: The root node to the parse tree.
"""
def tail_pos(predecessors: Union[List[Node], Tuple[Node, ...]]) -> int:
def tail_pos(predecessors: Union[List[Node], Tuple[Node, ...], None]) -> int:
"""Adds the position after the last node in the list of
predecessors to the node."""
return predecessors[-1].pos + len(predecessors[-1]) if predecessors else 0
......@@ -713,10 +713,11 @@ class Grammar:
str(HistoryRecord.last_match(self.history__)))
# Check if a Lookahead-Parser did match. Needed for testing, because
# in a test case this is not necessarily an error.
last_record = self.history__[-2] if len(self.history__) > 1 else []
last_record = self.history__[-2] if len(self.history__) > 1 else None # type: Optional[HistoryRecord]
if last_record and parser != self.root__ \
and last_record.status == HistoryRecord.MATCH \
and last_record.node.pos + len(last_record.node) >= len(self.document__) \
and last_record.node.pos \
+ len(last_record.node) >= len(self.document__) \
and any(isinstance(parser, Lookahead)
for parser in last_record.call_stack):
error_msg = 'Parser did not match except for lookahead! ' + err_info
......@@ -726,14 +727,14 @@ class Grammar:
error_code = Error.PARSER_DID_NOT_MATCH
else:
stitches.append(result)
error_msg = "Parser stopped before end" + \
(("! trying to recover" +
(" but stopping history recording at this point."
if self.history_tracking__ else "..."))
if len(stitches) < MAX_DROPOUTS
else " too often! Terminating parser.")
error_msg = "Parser stopped before end" \
+ (("! trying to recover"
+ (" but stopping history recording at this point."
if self.history_tracking__ else "..."))
if len(stitches) < MAX_DROPOUTS
else " too often! Terminating parser.")
error_code = Error.PARSER_STOPPED_BEFORE_END
stitches.append(Node(None, skip).init_pos(tail_pos(stitches or result)))
stitches.append(Node(None, skip).init_pos(tail_pos(stitches)))
self.tree__.new_error(stitches[-1], error_msg, error_code)
if self.history_tracking__:
# # some parsers may have matched and left history records with nodes != None.
......@@ -767,7 +768,8 @@ class Grammar:
self.tree__.new_error(result, error_msg, error_code)
# result.pos = 0 # calculate all positions
# result.collect_errors(self.document__)
self.tree__.swallow(result)
if result:
self.tree__.swallow(result)
return self.tree__
......@@ -847,7 +849,7 @@ class PreprocessorToken(Parser):
def __deepcopy__(self, memo):
duplicate = self.__class__(self.name)
duplicate.name = self.name
duplicate.ptype = self.ptype
duplicate.ptype = self.ptype
return duplicate
def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
......@@ -855,19 +857,22 @@ class PreprocessorToken(Parser):
end = text.find(END_TOKEN, 1)
if end < 0:
node = Node(self, '')
self.grammar.tree__.new_error(node,
self.grammar.tree__.new_error(
node,
'END_TOKEN delimiter missing from preprocessor token. '
'(Most likely due to a preprocessor bug!)') # type: Node
return node, text[1:]
elif end == 0:
node = Node(self, '')
self.grammar.tree__.new_error(node,
self.grammar.tree__.new_error(
node,
'Preprocessor-token cannot have zero length. '
'(Most likely due to a preprocessor bug!)')
return node, text[2:]
elif text.find(BEGIN_TOKEN, 1, end) >= 0:
node = Node(self, text[len(self.name) + 1:end])
self.grammar.tree__.new_error(node,
self.grammar.tree__.new_error(
node,
'Preprocessor-tokens must not be nested or contain '
'BEGIN_TOKEN delimiter as part of their argument. '
'(Most likely due to a preprocessor bug!)')
......@@ -941,7 +946,7 @@ class RegExp(Parser):
regexp = self.regexp.pattern
duplicate = self.__class__(regexp)
duplicate.name = self.name
duplicate.ptype = self.ptype
duplicate.ptype = self.ptype
return duplicate
def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
......@@ -962,7 +967,7 @@ class RegExp(Parser):
return escape_control_characters('/%s/' % self.regexp.pattern)
def withWS(parser_factory, wsL='', wsR='\s*'):
def withWS(parser_factory, wsL='', wsR=r'\s*'):
"""Syntactic Sugar for 'Series(Whitespace(wsL), parser_factory(), Whitespace(wsR))'.
"""
if wsL and isinstance(wsL, str):
......@@ -979,12 +984,12 @@ def withWS(parser_factory, wsL='', wsR='\s*'):
return parser_factory()
def RE(regexp, wsL='', wsR='\s*'):
def RE(regexp, wsL='', wsR=r'\s*'):
"""Syntactic Sugar for 'Series(Whitespace(wsL), RegExp(regexp), Whitespace(wsR))'"""
return withWS(lambda : RegExp(regexp), wsL, wsR)
return withWS(lambda: RegExp(regexp), wsL, wsR)
def TKN(token, wsL='', wsR='\s*'):
def TKN(token, wsL='', wsR=r'\s*'):
"""Syntactic Sugar for 'Series(Whitespace(wsL), Token(token), Whitespace(wsR))'"""
return withWS(lambda: Token(token), wsL, wsR)
......@@ -1026,7 +1031,7 @@ class UnaryOperator(Parser):
parser = copy.deepcopy(self.parser, memo)
duplicate = self.__class__(parser)
duplicate.name = self.name
duplicate.ptype = self.ptype
duplicate.ptype = self.ptype
return duplicate
def apply(self, func: Parser.ApplyFunc) -> bool:
......@@ -1057,7 +1062,7 @@ class NaryOperator(Parser):
parsers = copy.deepcopy(self.parsers, memo)
duplicate = self.__class__(*parsers)
duplicate.name = self.name
duplicate.ptype = self.ptype
duplicate.ptype = self.ptype
return duplicate
def apply(self, func: Parser.ApplyFunc) -> bool:
......@@ -1100,7 +1105,7 @@ class Option(UnaryOperator):
super().__init__(parser)
# assert isinstance(parser, Parser)
assert not isinstance(parser, Option), \
"Redundant nesting of options: %s" % (str(self.ptype), str(parser.name))
"Redundant nesting of options: %s%s" % (str(parser.name), str(self.ptype))
def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
node, text = self.parser(text)
......@@ -1245,7 +1250,7 @@ class Series(NaryOperator):
parsers = copy.deepcopy(self.parsers, memo)
duplicate = self.__class__(*parsers, mandatory=self.mandatory)
duplicate.name = self.name
duplicate.ptype = self.ptype
duplicate.ptype = self.ptype
return duplicate
def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
......@@ -1589,7 +1594,7 @@ class Lookbehind(FlowOperator):
p = p.parser
assert isinstance(p, RegExp) or isinstance(p, Token)
self.regexp = None
self.text = None
self.text = '' # type: str
if isinstance(p, RegExp):
self.regexp = cast(RegExp, p).regexp
else: # p is of type PlainText
......@@ -1686,7 +1691,7 @@ class Retrieve(Parser):
def __deepcopy__(self, memo):
duplicate = self.__class__(self.symbol, self.filter)
duplicate.name = self.name
duplicate.ptype = self.ptype
duplicate.ptype = self.ptype
return duplicate
def __call__(self, text: StringView) -> Tuple[Optional[Node], StringView]:
......@@ -1808,7 +1813,7 @@ class Forward(Parser):
def __deepcopy__(self, memo):
duplicate = self.__class__()
# duplicate.name = self.name # Forward-Parsers should never have a name!
duplicate.ptype = self.ptype
duplicate.ptype = self.ptype
memo[id(self)] = duplicate
parser = copy.deepcopy(self.parser, memo)
duplicate.set(parser)
......@@ -1854,4 +1859,3 @@ class Forward(Parser):
self.parser.apply(func)
return True
return False
......@@ -156,7 +156,6 @@ def strip_tokens(tokenized: str) -> str:
return ''.join(result)
#######################################################################
#
# Source Maps - mapping source code positions between different
......
......@@ -54,7 +54,7 @@ def last_char(text, begin: int, end: int) -> int:
"""Returns the index of the first non-whitespace character in string
`text` within the bounds [begin, end].
"""
while end > begin and text[end-1] in ' \n\t':
while end > begin and text[end - 1] in ' \n\t':
end -= 1
return end
......
......@@ -304,7 +304,7 @@ class Node(collections.abc.Sized):
mpargs = {'name': self.parser.name, 'ptype': self.parser.ptype}
parg = "MockParser({name}, {ptype})".format(**mpargs)
rarg = str(self) if not self.children else \
"(" + ", ".join(repr(child) for child in self.children) + ")"
"(" + ", ".join(repr(child) for child in self.children) + ")"
return "Node(%s, %s)" % (parg, rarg)
......@@ -650,7 +650,7 @@ class Node(collections.abc.Sized):
return ''
txt = ['<', node.tag_name]
has_reserved_attrs = hasattr(node, '_xml_attr') \
and any (r in node.attr for r in {'err', 'line', 'col'})
and any(r in node.attr for r in {'err', 'line', 'col'})
if hasattr(node, '_xml_attr'):
txt.extend(' %s="%s"' % (k, v) for k, v in node.attr.items())
if src and not has_reserved_attrs:
......@@ -911,7 +911,7 @@ def parse_sxpr(sxpr: Union[str, StringView]) -> Node:
'(a\\n (b\\n "c"\\n )\\n)'
"""
sxpr = StringView(sxpr).strip()
sxpr = StringView(sxpr).strip() if isinstance(sxpr, str) else sxpr.strip()
mock_parsers = dict() # type: Dict[str, MockParser]
def next_block(s: StringView):
......
......@@ -31,7 +31,6 @@ import collections
import copy
import fnmatch
import inspect
import itertools
import json
import os
import sys
......@@ -83,15 +82,15 @@ RESULT_STAGES = {'__cst__', '__ast__', '__err__'}
# # print(json.dumps(unit, sort_keys=True, indent=4))
# return unit
RX_SECTION = re.compile('\s*\[(?P<stage>\w+):(?P<symbol>\w+)\]')
RX_SECTION = re.compile(r'\s*\[(?P<stage>\w+):(?P<symbol>\w+)\]')
RE_VALUE = '(?:"""((?:.|\n)*?)""")|' + "(?:'''((?:.|\n)*?)''')|" + \
'(?:"(.*?)")|' + "(?:'(.*?)')|" + '(.*(?:\n(?:\s*\n)* .*)*)'
r'(?:"(.*?)")|' + "(?:'(.*?)')|" + r'(.*(?:\n(?:\s*\n)* .*)*)'
# the following does not work with pypy3, because pypy's re-engine does not
# support local flags, e.g. '(?s: )'
# RE_VALUE = '(?:"""((?s:.*?))""")|' + "(?:'''((?s:.*?))''')|" + \
# '(?:"(.*?)")|' + "(?:'(.*?)')|" + '(.*(?:\n(?:\s*\n)* .*)*)'
RX_ENTRY = re.compile('\s*(\w+\*?)\s*:\s*(?:{value})\s*'.format(value=RE_VALUE))
RX_COMMENT = re.compile('\s*#.*\n')
# RE_VALUE = r'(?:"""((?s:.*?))""")|' + "(?:'''((?s:.*?))''')|" + \
# r'(?:"(.*?)")|' + "(?:'(.*?)')|" + '(.*(?:\n(?:\s*\n)* .*)*)'
RX_ENTRY = re.compile(r'\s*(\w+\*?)\s*:\s*(?:{value})\s*'.format(value=RE_VALUE))
RX_COMMENT = re.compile(r'\s*#.*\n')
def unit_from_config(config_str):
......@@ -316,12 +315,12 @@ def grammar_unit(test_unit, parser_factory, transformer_factory, report=True, ve
lookahead operator at the end. See test_testing.TestLookahead.
"""
return len(raw_errors) == 2 \
and raw_errors[-1].code == Error.PARSER_LOOKAHEAD_MATCH_ONLY \
and raw_errors[-2].code == Error.PARSER_STOPPED_BEFORE_END
and raw_errors[-1].code == Error.PARSER_LOOKAHEAD_MATCH_ONLY \
and raw_errors[-2].code == Error.PARSER_STOPPED_BEFORE_END
for parser_name, tests in test_unit.items():
assert parser_name, "Missing parser name in test %s!" % unit_name
assert not any (test_type in RESULT_STAGES for test_type in tests), \
assert not any(test_type in RESULT_STAGES for test_type in tests), \
("Test %s in %s already has results. Use reset_unit() before running again!"
% (parser_name, unit_name))
assert set(tests.keys()).issubset(UNIT_STAGES), \
......@@ -562,4 +561,3 @@ def runner(test_classes, namespace):
for test in test_functions:
exec(test + '()', namespace)
......@@ -22,9 +22,9 @@ several of the the other DHParser-Modules or that are just very generic
so that they are best defined in a toolkit-module.
"""
import codecs
# import codecs
import hashlib
import io
# import io
import multiprocessing
import parser
import threading
......@@ -41,7 +41,7 @@ except ImportError:
import DHParser.foreign_typing as typing
sys.modules['typing'] = typing # make it possible to import from typing
from typing import Any, Iterable, Sequence, Set, Union, Dict, cast
from typing import Any, Iterable, Sequence, Set, Union, Dict # , cast
__all__ = ('escape_re',
......@@ -207,13 +207,13 @@ def has_fenced_code(text_or_file: str, info_strings=('ebnf', 'test')) -> bool:
if isinstance(info_strings, str):
info_strings = (info_strings,)
fence_tmpl = '\n(?:(?:``[`]*[ ]*(?:%s)(?=[ .\-:\n])[^`\n]*\n)' + \
'|(?:~~[~]*[ ]*(?:%s)(?=[ .\-:\n])[\n]*\n))'
fence_tmpl = r'\n(?:(?:``[`]*[ ]*(?:%s)(?=[ .\-:\n])[^`\n]*\n)' + \
r'|(?:~~[~]*[ ]*(?:%s)(?=[ .\-:\n])[\n]*\n))'
label_re = '|'.join('(?:%s)' % matched_string for matched_string in info_strings)
rx_fence = re.compile(fence_tmpl % (label_re, label_re), flags=re.IGNORECASE)
for match in rx_fence.finditer(markdown):
matched_string = re.match('(?:\n`+)|(?:\n~+)', match.group(0)).group(0)
matched_string = re.match(r'(?:\n`+)|(?:\n~+)', match.group(0)).group(0)
if markdown.find(matched_string, match.end()) >= 0:
return True
else:
......@@ -333,7 +333,6 @@ def expand_table(compact_table: Dict) -> Dict:
return expanded_table
#######################################################################
#
# miscellaneous (DHParser-specific)
......
......@@ -29,12 +29,11 @@ for CST -> AST transformations.
import collections.abc
import inspect
import fnmatch
from functools import partial, reduce, singledispatch
from functools import partial, singledispatch
from DHParser.error import Error, ErrorCode
from DHParser.syntaxtree import Node, WHITESPACE_PTYPE, TOKEN_PTYPE, ParserBase, MockParser, \
ZOMBIE_NODE, parse_sxpr, flatten_sxpr
ZOMBIE_NODE, RootNode, parse_sxpr, flatten_sxpr
from DHParser.toolkit import issubtype, isgenerictype, expand_table, smart_list, re, typing
from typing import AbstractSet, Any, ByteString, Callable, cast, Container, Dict, \
Tuple, List, Sequence, Union, Text, Generic
......@@ -240,7 +239,7 @@ def key_tag_name(node: Node) -> str:
def traverse(root_node: Node,
processing_table: ProcessingTableType,
key_func: KeyFunc=key_tag_name) -> None:
key_func: KeyFunc = key_tag_name) -> None:
"""
Traverses the snytax tree starting with the given ``node`` depth
first and applies the sequences of callback-functions registered
......@@ -292,9 +291,10 @@ def traverse(root_node: Node,
assert '+' not in table, 'Symbol "+" in processing table is obsolete, use "<" instead'
if '~' in table:
if ':Whitespace' in table:
raise AssertionError('"~" is a synonym for ":Whitespace" in the '
'processing table. To avoid confusion, choose either of the two, '
'but do not use both at the same time!')
raise AssertionError(
'"~" is a synonym for ":Whitespace" in the processing table. '
'To avoid confusion, choose either of the two, but do not use '
'both at the same time!')
whitespace_transformation = table['~']
del table['~']
table[':Whitespace'] = whitespace_transformation
......@@ -341,8 +341,8 @@ def traverse(root_node: Node,
@transformation_factory(dict)
def traverse_locally(context: List[Node],
processing_table: Dict, # actually: ProcessingTableType
key_func: Callable=key_tag_name): # actually: KeyFunc
processing_table: Dict, # actually: ProcessingTableType
key_func: Callable = key_tag_name): # actually: KeyFunc
"""
Transforms the syntax tree starting from the last node in the context
according to the given processing table. The purpose of this function is
......@@ -572,7 +572,7 @@ def reduce_single_child(context: List[Node]):
@transformation_factory(collections.abc.Callable)
def replace_or_reduce(context: List[Node], condition: Callable=is_named):
def replace_or_reduce(context: List[Node], condition: Callable = is_named):
"""
Replaces node by a single child, if condition is met on child,
otherwise (i.e. if the child is anonymous) reduces the child.
......@@ -602,7 +602,7 @@ def replace_parser(context: List[Node], name: str):
@transformation_factory(collections.abc.Callable)
def flatten(context: List[Node], condition: Callable=is_anonymous, recursive: bool=True):
def flatten(context: List[Node], condition: Callable = is_anonymous, recursive: bool = True):
"""
Flattens all children, that fulfill the given ``condition``
(default: all unnamed children). Flattening means that wherever a
......@@ -664,8 +664,8 @@ def collapse_if(context: List[Node], condition: Callable, target_tag: ParserBase
"""
node = context[-1]
package = []
result = []
package = [] # type: List[Node]
result = [] # type: List[Node]
def close_package():
nonlocal package
......@@ -726,7 +726,7 @@ def normalize_whitespace(context):
if node.result:
node.result = ' '
else:
node.result = re.sub('\s+', ' ', node.result)
node.result = re.sub(r'\s+', ' ', node.result)
def move_whitespace(context):
......@@ -756,8 +756,8 @@ def move_whitespace(context):
break
# merge adjacent whitespace
prevN = parent.children[i-1] if i > 0 else None
nextN = parent.children[i+1] if i < len(parent.children)-1 else None
prevN = parent.children[i - 1] if i > 0 else None
nextN = parent.children[i + 1] if i < len(parent.children) - 1 else None
if before and prevN and prevN.parser.ptype == WHITESPACE_PTYPE:
prevN.result = prevN.result + before[0].result
before = ()
......@@ -765,7 +765,7 @@ def move_whitespace(context):
nextN.result = after[0].result + nextN.result
after = ()
parent.result = parent.children[:i] + before + (node,) + after + parent.children[i+1:]
parent.result = parent.children[:i] + before + (node,) + after + parent.children[i + 1:]
#######################################################################
......@@ -802,7 +802,7 @@ def rstrip(context: List[Node], condition: Callable = is_expendable):
rstrip(context + [node.children[-1]], condition)
L = len(node.children)
i = L
while i > 0 and condition(context + [node.children[i-1]]):
while i > 0 and condition(context + [node.children[i - 1]]):
i -= 1
if i < L:
node.result = node.children[:i]
......@@ -832,7 +832,7 @@ def keep_children_if(context: List[Node], condition: Callable):
@transformation_factory(collections.abc.Set)
def keep_tokens(context: List[Node], tokens: AbstractSet[str]=frozenset()):
def keep_tokens(context: List[Node], tokens: AbstractSet[str] = frozenset()):
"""Removes any among a particular set of tokens from the immediate