10.12., 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit f414983c authored by di68kap's avatar di68kap

- work in progress!

parent ce75dc7b
...@@ -56,7 +56,8 @@ import threading ...@@ -56,7 +56,8 @@ import threading
from DHParser.error import line_col from DHParser.error import line_col
from DHParser.stringview import StringView from DHParser.stringview import StringView
from DHParser.syntaxtree import Node, ParserBase from DHParser.syntaxtree import Node
from DHParser.parse import ParserBase
from DHParser.toolkit import is_filename, escape_control_characters, GLOBALS, typing from DHParser.toolkit import is_filename, escape_control_characters, GLOBALS, typing
from typing import List, Tuple, Union from typing import List, Tuple, Union
......
...@@ -37,8 +37,8 @@ from DHParser.error import Error, linebreaks ...@@ -37,8 +37,8 @@ from DHParser.error import Error, linebreaks
from DHParser.log import is_logging, HistoryRecord from DHParser.log import is_logging, HistoryRecord
from DHParser.preprocess import BEGIN_TOKEN, END_TOKEN, RX_TOKEN_NAME from DHParser.preprocess import BEGIN_TOKEN, END_TOKEN, RX_TOKEN_NAME
from DHParser.stringview import StringView, EMPTY_STRING_VIEW from DHParser.stringview import StringView, EMPTY_STRING_VIEW
from DHParser.syntaxtree import Node, RootNode, ParserBase, WHITESPACE_PTYPE, \ from DHParser.syntaxtree import Node, RootNode, WHITESPACE_PTYPE, \
TOKEN_PTYPE, ZOMBIE_PARSER, ZOMBIE, ResultType TOKEN_PTYPE, ZOMBIE, ResultType
from DHParser.toolkit import sane_parser_name, escape_control_characters, re, typing from DHParser.toolkit import sane_parser_name, escape_control_characters, re, typing
from typing import Callable, cast, List, Tuple, Set, Dict, DefaultDict, Union, Optional, Any from typing import Callable, cast, List, Tuple, Set, Dict, DefaultDict, Union, Optional, Any
...@@ -147,6 +147,50 @@ ApplyFunc = Callable[['Parser'], None] ...@@ -147,6 +147,50 @@ ApplyFunc = Callable[['Parser'], None]
FlagFunc = Callable[[ApplyFunc, Set[ApplyFunc]], bool] FlagFunc = Callable[[ApplyFunc, Set[ApplyFunc]], bool]
class ParserBase:
"""
ParserBase is the base class for all real and mock parser classes.
It is defined here, because Node objects require a parser object
for instantiation.
"""
__slots__ = 'name', 'ptype', 'tag_name'
def __init__(self,): # , pbases=frozenset()):
self.name = '' # type: str
self.ptype = ':' + self.__class__.__name__ # type: str
self.tag_name = self.ptype # type: str
def __repr__(self):
return self.name + self.ptype
def __str__(self):
return self.name + (' = ' if self.name else '') + repr(self)
def __call__(self, text: StringView) -> Tuple[Optional['Node'], StringView]:
return None, text
@property
def repr(self) -> str:
"""Returns the parser's name if it has a name and repr()"""
return self.name if self.name else self.__repr__()
def reset(self):
"""Resets any parser variables. (Should be overridden.)"""
pass
@property
def grammar(self) -> 'Grammar':
"""Returns the Grammar object to which the parser belongs. If not
yet connected to any Grammar object, None is returned."""
raise NotImplementedError
def apply(self, func: Callable):
"""Applies the function `func` recursively to the parser and all
descendant parsers, if any exist."""
pass
class Parser(ParserBase): class Parser(ParserBase):
""" """
(Abstract) Base class for Parser combinator parsers. Any parser (Abstract) Base class for Parser combinator parsers. Any parser
...@@ -2103,3 +2147,59 @@ class Forward(Parser): ...@@ -2103,3 +2147,59 @@ class Forward(Parser):
self.parser._apply(func, flip) self.parser._apply(func, flip)
return True return True
return False return False
class MockParser(ParserBase):
"""
MockParser objects can be used to reconstruct syntax trees from a
serialized form like S-expressions or XML. Mock objects can mimic
different parser types by assigning them a `ptype` on initialization.
Mock objects should not be used for anything other than
syntax tree (re-)construction. In all other cases where a parser
object substitute is needed, chose the singleton ZOMBIE_PARSER.
"""
__slots__ = ()
def __init__(self, name='', ptype=''): # , pbases=frozenset()):
assert not ptype or ptype[0] == ':'
super().__init__()
self.name = name
if ptype:
self.ptype = ptype # or ':' + self.__class__.__name__
class ZombieParser(MockParser):
"""
Serves as a substitute for a Parser instance.
``ZombieParser`` is the class of the singelton object
``ZOMBIE_PARSER``. The ``ZOMBIE_PARSER`` has a name and can be
called, but it never matches. It serves as a substitute where only
these (or one of these properties) is needed, but no real Parser-
object is instantiated.
"""
alive = False
__slots__ = ()
def __init__(self):
super(ZombieParser, self).__init__()
assert not self.__class__.alive, "There can be only one!"
assert self.__class__ == ZombieParser, "No derivatives, please!"
self.name = ZOMBIE
self.__class__.alive = True
def __copy__(self):
return self
def __deepcopy__(self, memo):
return self
def __call__(self, text):
"""Better call Saul ;-)"""
return None, text
ZOMBIE_PARSER = ZombieParser()
\ No newline at end of file
...@@ -23,24 +23,18 @@ here, because node-objects refer to parser-objects. All concrete ...@@ -23,24 +23,18 @@ here, because node-objects refer to parser-objects. All concrete
parser classes are defined in the ``parse`` module. parser classes are defined in the ``parse`` module.
""" """
import collections.abc
from collections import OrderedDict from collections import OrderedDict
import copy import copy
from DHParser.error import Error, ErrorCode, linebreaks, line_col from DHParser.error import Error, ErrorCode, linebreaks, line_col
from DHParser.stringview import StringView from DHParser.stringview import StringView
from DHParser.toolkit import re, typing from DHParser.toolkit import re
from typing import Callable, cast, Iterator, List, AbstractSet, Set, Dict, Union, Tuple, Optional from typing import Callable, cast, Iterator, List, AbstractSet, Set, Union, Tuple, Optional
__all__ = ('ParserBase', __all__ = ('WHITESPACE_PTYPE',
'WHITESPACE_PTYPE',
'TOKEN_PTYPE', 'TOKEN_PTYPE',
'MockParser',
'ZombieParser',
'ZOMBIE', 'ZOMBIE',
'ZOMBIE_PARSER',
'ZOMBIE_NODE', 'ZOMBIE_NODE',
'ResultType', 'ResultType',
'StrictResultType', 'StrictResultType',
...@@ -61,113 +55,11 @@ __all__ = ('ParserBase', ...@@ -61,113 +55,11 @@ __all__ = ('ParserBase',
####################################################################### #######################################################################
class ParserBase:
"""
ParserBase is the base class for all real and mock parser classes.
It is defined here, because Node objects require a parser object
for instantiation.
"""
__slots__ = 'name', 'ptype', 'tag_name'
def __init__(self,): # , pbases=frozenset()):
self.name = '' # type: str
self.ptype = ':' + self.__class__.__name__ # type: str
self.tag_name = self.ptype # type: str
def __repr__(self):
return self.name + self.ptype
def __str__(self):
return self.name + (' = ' if self.name else '') + repr(self)
def __call__(self, text: StringView) -> Tuple[Optional['Node'], StringView]:
return None, text
@property
def repr(self) -> str:
"""Returns the parser's name if it has a name and repr()"""
return self.name if self.name else self.__repr__()
def reset(self):
"""Resets any parser variables. (Should be overridden.)"""
pass
@property
def grammar(self) -> 'Grammar':
"""Returns the Grammar object to which the parser belongs. If not
yet connected to any Grammar object, None is returned."""
raise NotImplementedError
def apply(self, func: Callable):
"""Applies the function `func` recursively to the parser and all
descendant parsers, if any exist."""
pass
WHITESPACE_PTYPE = ':Whitespace' WHITESPACE_PTYPE = ':Whitespace'
TOKEN_PTYPE = ':Token' TOKEN_PTYPE = ':Token'
class MockParser(ParserBase):
"""
MockParser objects can be used to reconstruct syntax trees from a
serialized form like S-expressions or XML. Mock objects can mimic
different parser types by assigning them a `ptype` on initialization.
Mock objects should not be used for anything other than
syntax tree (re-)construction. In all other cases where a parser
object substitute is needed, chose the singleton ZOMBIE_PARSER.
"""
__slots__ = ()
def __init__(self, name='', ptype=''): # , pbases=frozenset()):
assert not ptype or ptype[0] == ':'
super().__init__()
self.name = name
if ptype:
self.ptype = ptype # or ':' + self.__class__.__name__
ZOMBIE = "__ZOMBIE__" ZOMBIE = "__ZOMBIE__"
class ZombieParser(MockParser):
"""
Serves as a substitute for a Parser instance.
``ZombieParser`` is the class of the singelton object
``ZOMBIE_PARSER``. The ``ZOMBIE_PARSER`` has a name and can be
called, but it never matches. It serves as a substitute where only
these (or one of these properties) is needed, but no real Parser-
object is instantiated.
"""
alive = False
__slots__ = ()
def __init__(self):
super(ZombieParser, self).__init__()
assert not self.__class__.alive, "There can be only one!"
assert self.__class__ == ZombieParser, "No derivatives, please!"
self.name = ZOMBIE
self.__class__.alive = True
def __copy__(self):
return self
def __deepcopy__(self, memo):
return self
def __call__(self, text):
"""Better call Saul ;-)"""
return None, text
ZOMBIE_PARSER = ZombieParser()
####################################################################### #######################################################################
# #
# syntaxtree nodes # syntaxtree nodes
......
...@@ -32,8 +32,8 @@ import inspect ...@@ -32,8 +32,8 @@ import inspect
from functools import partial, singledispatch from functools import partial, singledispatch
from DHParser.error import Error, ErrorCode from DHParser.error import Error, ErrorCode
from DHParser.syntaxtree import Node, WHITESPACE_PTYPE, TOKEN_PTYPE, ParserBase, MockParser, \ from DHParser.syntaxtree import Node, WHITESPACE_PTYPE, TOKEN_PTYPE, ZOMBIE_NODE, RootNode, parse_sxpr, flatten_sxpr
ZOMBIE_NODE, RootNode, parse_sxpr, flatten_sxpr from DHParser.parse import ParserBase, MockParser
from DHParser.toolkit import issubtype, isgenerictype, expand_table, smart_list, re, typing from DHParser.toolkit import issubtype, isgenerictype, expand_table, smart_list, re, typing
from typing import AbstractSet, Any, ByteString, Callable, cast, Container, Dict, \ from typing import AbstractSet, Any, ByteString, Callable, cast, Container, Dict, \
Tuple, List, Sequence, Union, Text, Generic Tuple, List, Sequence, Union, Text, Generic
......
...@@ -32,8 +32,8 @@ from DHParser import logging, is_filename, load_if_file, \ ...@@ -32,8 +32,8 @@ from DHParser import logging, is_filename, load_if_file, \
is_empty, is_expendable, collapse, replace_content, WHITESPACE_PTYPE, TOKEN_PTYPE, \ is_empty, is_expendable, collapse, replace_content, WHITESPACE_PTYPE, TOKEN_PTYPE, \
remove_nodes, remove_content, remove_brackets, replace_parser, remove_anonymous_tokens, \ remove_nodes, remove_content, remove_brackets, replace_parser, remove_anonymous_tokens, \
keep_children, is_one_of, has_content, apply_if, remove_first, remove_last, \ keep_children, is_one_of, has_content, apply_if, remove_first, remove_last, \
remove_anonymous_empty, keep_nodes, traverse_locally, strip, lstrip, rstrip, MockParser, \ remove_anonymous_empty, keep_nodes, traverse_locally, strip, lstrip, rstrip, ZOMBIE_NODE
ZOMBIE_NODE from DHParser.parse import MockParser
####################################################################### #######################################################################
...@@ -574,7 +574,7 @@ class XMLCompiler(Compiler): ...@@ -574,7 +574,7 @@ class XMLCompiler(Compiler):
if attributes: if attributes:
node.attr.update(attributes) node.attr.update(attributes)
preserve_whitespace |= attributes.get('xml:space', '') == 'preserve' preserve_whitespace |= attributes.get('xml:space', '') == 'preserve'
node.parser = self.get_parser(tag_name) node.tag_name = tag_name
content = self.compile_children(node.get('content', ZOMBIE_NODE)) content = self.compile_children(node.get('content', ZOMBIE_NODE))
if len(content) == 1: if len(content) == 1:
if content[0].tag_name == "CharData": if content[0].tag_name == "CharData":
......
...@@ -18,8 +18,7 @@ try: ...@@ -18,8 +18,7 @@ try:
import regex as re import regex as re
except ImportError: except ImportError:
import re import re
from DHParser import logging, is_filename, load_if_file, MockParser, \ from DHParser import logging, is_filename, load_if_file, Grammar, Compiler, nil_preprocessor, PreprocessorToken, Whitespace, \
Grammar, Compiler, nil_preprocessor, PreprocessorToken, Whitespace, \
Lookbehind, Lookahead, Alternative, Pop, Token, Synonym, AllOf, SomeOf, Unordered, \ Lookbehind, Lookahead, Alternative, Pop, Token, Synonym, AllOf, SomeOf, Unordered, \
Option, NegativeLookbehind, OneOrMore, RegExp, Retrieve, Series, Capture, \ Option, NegativeLookbehind, OneOrMore, RegExp, Retrieve, Series, Capture, \
ZeroOrMore, Forward, NegativeLookahead, Required, mixin_comment, compile_source, \ ZeroOrMore, Forward, NegativeLookahead, Required, mixin_comment, compile_source, \
...@@ -34,6 +33,7 @@ from DHParser import logging, is_filename, load_if_file, MockParser, \ ...@@ -34,6 +33,7 @@ from DHParser import logging, is_filename, load_if_file, MockParser, \
remove_anonymous_empty, keep_nodes, traverse_locally, strip, lstrip, rstrip, \ remove_anonymous_empty, keep_nodes, traverse_locally, strip, lstrip, rstrip, \
replace_content, replace_content_by, forbid, assert_content, remove_infix_operator, \ replace_content, replace_content_by, forbid, assert_content, remove_infix_operator, \
error_on, recompile_grammar, GLOBALS error_on, recompile_grammar, GLOBALS
from DHParser.parse import MockParser
####################################################################### #######################################################################
......
...@@ -23,8 +23,8 @@ import copy ...@@ -23,8 +23,8 @@ import copy
import sys import sys
sys.path.extend(['../', './']) sys.path.extend(['../', './'])
from DHParser.syntaxtree import Node, RootNode, parse_sxpr, parse_xml, flatten_sxpr, flatten_xml, \ from DHParser.syntaxtree import Node, RootNode, parse_sxpr, parse_xml, flatten_sxpr, flatten_xml
MockParser from DHParser.parse import MockParser
from DHParser.transform import traverse, reduce_single_child, \ from DHParser.transform import traverse, reduce_single_child, \
replace_by_single_child, flatten, remove_expendables replace_by_single_child, flatten, remove_expendables
from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler
......
...@@ -25,7 +25,8 @@ import sys ...@@ -25,7 +25,8 @@ import sys
sys.path.extend(['../', './']) sys.path.extend(['../', './'])
from DHParser.syntaxtree import Node, parse_sxpr, flatten_sxpr, parse_xml, ZOMBIE_NODE, \ from DHParser.syntaxtree import Node, parse_sxpr, flatten_sxpr, parse_xml, ZOMBIE_NODE, \
MockParser, TOKEN_PTYPE TOKEN_PTYPE
from DHParser.parse import MockParser
from DHParser.transform import traverse, reduce_single_child, remove_whitespace, \ from DHParser.transform import traverse, reduce_single_child, remove_whitespace, \
traverse_locally, collapse, collapse_if, lstrip, rstrip, remove_content, remove_tokens, \ traverse_locally, collapse, collapse_if, lstrip, rstrip, remove_content, remove_tokens, \
transformation_factory, has_parent transformation_factory, has_parent
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment