Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
badw-it
DHParser
Commits
9d301e10
Commit
9d301e10
authored
Jan 06, 2019
by
eckhart
Browse files
- mypy type errors corrected
parent
72976d8f
Changes
4
Show whitespace changes
Inline
Side-by-side
DHParser/parse.py
View file @
9d301e10
...
@@ -256,6 +256,10 @@ def add_parser_guard(parser_func):
...
@@ -256,6 +256,10 @@ def add_parser_guard(parser_func):
return
guarded_call
return
guarded_call
ApplyFunc
=
Callable
[[
'Parser'
],
None
]
FlagFunc
=
Callable
[[
ApplyFunc
,
Set
[
ApplyFunc
]],
bool
]
class
Parser
(
ParserBase
):
class
Parser
(
ParserBase
):
"""
"""
(Abstract) Base class for Parser combinator parsers. Any parser
(Abstract) Base class for Parser combinator parsers. Any parser
...
@@ -314,8 +318,6 @@ class Parser(ParserBase):
...
@@ -314,8 +318,6 @@ class Parser(ParserBase):
is attached.
is attached.
"""
"""
ApplyFunc
=
Callable
[[
'Parser'
],
None
]
def
__init__
(
self
)
->
None
:
def
__init__
(
self
)
->
None
:
# assert isinstance(name, str), str(name)
# assert isinstance(name, str), str(name)
super
().
__init__
()
super
().
__init__
()
...
@@ -350,7 +352,7 @@ class Parser(ParserBase):
...
@@ -350,7 +352,7 @@ class Parser(ParserBase):
`reset()`-method of the derived class."""
`reset()`-method of the derived class."""
self
.
visited
=
dict
()
# type: Dict[int, Tuple[Optional[Node], StringView]]
self
.
visited
=
dict
()
# type: Dict[int, Tuple[Optional[Node], StringView]]
self
.
recursion_counter
=
defaultdict
(
lambda
:
0
)
# type: DefaultDict[int, int]
self
.
recursion_counter
=
defaultdict
(
lambda
:
0
)
# type: DefaultDict[int, int]
self
.
cycle_detection
=
set
()
# type: Set[
Callable
]
self
.
cycle_detection
=
set
()
# type: Set[
ApplyFunc
]
def
__call__
(
self
,
text
:
StringView
)
->
Tuple
[
Optional
[
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
...
@@ -390,23 +392,55 @@ class Parser(ParserBase):
...
@@ -390,23 +392,55 @@ class Parser(ParserBase):
assigned to a grammar."""
assigned to a grammar."""
pass
pass
def
apply
(
self
,
func
:
ApplyFunc
)
->
bool
:
def
_
apply
(
self
,
func
:
ApplyFunc
,
flip
:
FlagFunc
)
->
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.
be applied twice between calls of the ``reset()``-method!
Returns `True`, if function has been applied, `False` if function
In order to break cycles, function `flip` is called, which should
had been applied earlier already and thus has not been applied again.
return `True`, if this parser has already been visited. If not, it
flips the cycle detection flag and returns `False`.
This is a protected function and should not called from outside
class Parser or any of its descendants. The entry point for external
calls is the method `apply()` without underscore!
"""
"""
if
f
unc
in
self
.
cycle_detection
:
if
f
lip
(
func
,
self
.
cycle_detection
)
:
return
False
return
False
else
:
else
:
assert
not
self
.
visited
,
"No calls to Parser.apply() during or "
\
"after ongoing parsing process. (Call Parser.reset() first.)"
self
.
cycle_detection
.
add
(
func
)
func
(
self
)
func
(
self
)
return
True
return
True
def
apply
(
self
,
func
:
ApplyFunc
):
"""
Applies function `func(parser)` recursively to this parser and all
descendant parsers, if any exist. Traversal is pre-order.
"""
def
positive_flip
(
f
:
ApplyFunc
,
flagged
:
Set
[
Callable
])
->
bool
:
"""Returns True, if function `f` has already been applied to this
parser and sets the flag accordingly. Interprets `f in flagged == True`
as meaning that `f` has already been applied."""
if
f
in
flagged
:
return
True
else
:
flagged
.
add
(
f
)
return
False
def
negative_flip
(
f
:
ApplyFunc
,
flagged
:
Set
[
Callable
])
->
bool
:
"""Returns True, if function `f` has already been applied to this
parser and sets the flag accordingly. Interprets `f in flagged == False`
as meaning that `f` has already been applied."""
if
f
not
in
flagged
:
return
True
else
:
flagged
.
remove
(
f
)
return
False
if
func
in
self
.
cycle_detection
:
self
.
_apply
(
func
,
negative_flip
)
else
:
self
.
_apply
(
func
,
positive_flip
)
def
mixin_comment
(
whitespace
:
str
,
comment
:
str
)
->
str
:
def
mixin_comment
(
whitespace
:
str
,
comment
:
str
)
->
str
:
"""
"""
...
@@ -1134,9 +1168,9 @@ class UnaryOperator(Parser):
...
@@ -1134,9 +1168,9 @@ class UnaryOperator(Parser):
duplicate
.
ptype
=
self
.
ptype
duplicate
.
ptype
=
self
.
ptype
return
duplicate
return
duplicate
def
apply
(
self
,
func
:
Parser
.
Apply
Func
)
->
bool
:
def
_
apply
(
self
,
func
:
ApplyFunc
,
flip
:
Flag
Func
)
->
bool
:
if
super
().
apply
(
func
):
if
super
().
_
apply
(
func
,
flip
):
self
.
parser
.
apply
(
func
)
self
.
parser
.
_
apply
(
func
,
flip
)
return
True
return
True
return
False
return
False
...
@@ -1165,10 +1199,10 @@ class NaryOperator(Parser):
...
@@ -1165,10 +1199,10 @@ class NaryOperator(Parser):
duplicate
.
ptype
=
self
.
ptype
duplicate
.
ptype
=
self
.
ptype
return
duplicate
return
duplicate
def
apply
(
self
,
func
:
Parser
.
Apply
Func
)
->
bool
:
def
_
apply
(
self
,
func
:
ApplyFunc
,
flip
:
Flag
Func
)
->
bool
:
if
super
().
apply
(
func
):
if
super
().
_
apply
(
func
,
flip
):
for
parser
in
self
.
parsers
:
for
parser
in
self
.
parsers
:
parser
.
apply
(
func
)
parser
.
_
apply
(
func
,
flip
)
return
True
return
True
return
False
return
False
...
@@ -1979,8 +2013,8 @@ class Forward(Parser):
...
@@ -1979,8 +2013,8 @@ class Forward(Parser):
"""
"""
self
.
parser
=
parser
self
.
parser
=
parser
def
apply
(
self
,
func
:
Parser
.
Apply
Func
)
->
bool
:
def
_
apply
(
self
,
func
:
ApplyFunc
,
flip
:
Flag
Func
)
->
bool
:
if
super
().
apply
(
func
):
if
super
().
_
apply
(
func
,
flip
):
self
.
parser
.
apply
(
func
)
self
.
parser
.
_
apply
(
func
,
flip
)
return
True
return
True
return
False
return
False
DHParser/syntaxtree.py
View file @
9d301e10
...
@@ -97,11 +97,10 @@ class ParserBase:
...
@@ -97,11 +97,10 @@ class ParserBase:
yet connected to any Grammar object, None is returned."""
yet connected to any Grammar object, None is returned."""
raise
NotImplementedError
raise
NotImplementedError
def
apply
(
self
,
func
:
Callable
)
->
bool
:
def
apply
(
self
,
func
:
Callable
):
"""Applies the function `func` to the parser. Returns False, if
"""Applies the function `func` recursively to the parser and all
- for whatever reason - the functions has not been applied, True
descendant parsers, if any exist."""
otherwise."""
pass
return
False
WHITESPACE_PTYPE
=
':Whitespace'
WHITESPACE_PTYPE
=
':Whitespace'
...
...
DHParser/testing.py
View file @
9d301e10
...
@@ -311,7 +311,7 @@ def grammar_unit(test_unit, parser_factory, transformer_factory, report=True, ve
...
@@ -311,7 +311,7 @@ def grammar_unit(test_unit, parser_factory, transformer_factory, report=True, ve
def
lookahead_artifact
(
raw_errors
):
def
lookahead_artifact
(
raw_errors
):
"""
"""
Returns True, if the error merely occured, because the parser
Returns True, if the error merely occured, because the parser
stopped in front of a se
u
qence that was captured by a lookahead
stopped in front of a seq
u
ence that was captured by a lookahead
operator. This is required for testing of parsers that put a
operator. This is required for testing of parsers that put a
lookahead operator at the end. See test_testing.TestLookahead.
lookahead operator at the end. See test_testing.TestLookahead.
"""
"""
...
...
test/test_parse.py
View file @
9d301e10
...
@@ -27,13 +27,37 @@ sys.path.extend(['../', './'])
...
@@ -27,13 +27,37 @@ sys.path.extend(['../', './'])
from
DHParser.toolkit
import
compile_python_object
from
DHParser.toolkit
import
compile_python_object
from
DHParser.log
import
logging
,
is_logging
,
log_ST
from
DHParser.log
import
logging
,
is_logging
,
log_ST
from
DHParser.error
import
Error
from
DHParser.error
import
Error
from
DHParser.parse
import
Retrieve
,
Grammar
,
Forward
,
TKN
,
ZeroOrMore
,
RE
,
\
from
DHParser.parse
import
Retrieve
,
Parser
,
Grammar
,
Forward
,
TKN
,
ZeroOrMore
,
RE
,
\
RegExp
,
Lookbehind
,
NegativeLookahead
,
OneOrMore
,
Series
,
Alternative
,
AllOf
,
SomeOf
,
UnknownParserError
RegExp
,
Lookbehind
,
NegativeLookahead
,
OneOrMore
,
Series
,
Alternative
,
AllOf
,
SomeOf
,
\
UnknownParserError
from
DHParser
import
compile_source
from
DHParser
import
compile_source
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
from
DHParser.dsl
import
grammar_provider
,
DHPARSER_IMPORTS
from
DHParser.dsl
import
grammar_provider
,
DHPARSER_IMPORTS
class
TestParserClass
:
def
test_apply
(
self
):
minilang
=
"""
expr = expr ("+"|"-") term | term
term = term ("*"|"/") factor | factor
factor = /[0-9]+/~
"""
gr
=
grammar_provider
(
minilang
)()
l
=
[]
def
visitor
(
p
:
Parser
):
l
.
append
(
p
.
name
+
p
.
ptype
)
gr
.
root__
.
apply
(
visitor
)
s1
=
", "
.
join
(
l
)
l
=
[]
gr
.
root__
.
apply
(
visitor
)
s2
=
", "
.
join
(
l
)
l
=
[]
gr
.
root__
.
apply
(
visitor
)
s3
=
", "
.
join
(
l
)
# print(s1); print(s2); print(s3)
assert
s1
==
s2
==
s3
class
TestInfiLoopsAndRecursion
:
class
TestInfiLoopsAndRecursion
:
def
test_direct_left_recursion1
(
self
):
def
test_direct_left_recursion1
(
self
):
minilang
=
"""
minilang
=
"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment