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
1c999dbb
Commit
1c999dbb
authored
Mar 05, 2020
by
di68kap
Browse files
parse.py: bug fixes and tests
parent
adbbd2e6
Changes
2
Hide whitespace changes
Inline
Side-by-side
DHParser/parse.py
View file @
1c999dbb
...
...
@@ -488,14 +488,27 @@ class Parser:
def
__add__
(
self
,
other
:
'Parser'
)
->
'Series'
:
"""The + operator generates a series-parser that applies two
parsers in sequence."""
if
isinstance
(
other
,
Series
):
return
cast
(
'Series'
,
other
).
__radd__
(
self
)
return
Series
(
self
,
other
)
def
__or__
(
self
,
other
:
'Parser'
)
->
'Alternative'
:
"""The | operator generates an alternative parser that applies
the first parser and, if that does not match, the second parser.
"""
if
isinstance
(
other
,
Alternative
):
return
cast
(
'Alternative'
,
other
).
__ror__
(
self
)
return
Alternative
(
self
,
other
)
def
__mul__
(
self
,
other
:
'Parser'
)
->
'Alternative'
:
"""The * operator generates an interleave parser that applies
the first parser and the second parser in any possible order
until both match.
"""
if
isinstance
(
other
,
Interleave
):
return
cast
(
Interleave
,
other
).
__rmul__
(
self
)
return
Interleave
(
self
,
other
)
def
_parse
(
self
,
text
:
StringView
)
->
Tuple
[
Optional
[
Node
],
StringView
]:
"""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
...
...
@@ -2217,12 +2230,9 @@ class AllOf(MandatoryNary):
del
parsers
[
i
]
break
else
:
# TODO: Should mandatory-semantics be changed for AllOf to match that of Interleave???
for
i
,
p
in
enumerate
(
self
.
parsers
):
if
p
in
parsers
and
i
<
self
.
mandatory
:
return
None
,
text
# if self.num_parsers - len(parsers) < self.mandatory:
# return None, text
reloc
=
self
.
get_reentry_point
(
text_
)
expected
=
'< '
+
' '
.
join
([
parser
.
repr
for
parser
in
parsers
])
+
' >'
error
,
err_node
,
text_
=
self
.
mandatory_violation
(
text_
,
False
,
expected
,
reloc
)
...
...
@@ -2309,13 +2319,14 @@ def Unordered(parser: NaryParser) -> NaryParser:
class
Interleave
(
MandatoryNary
):
"""EXPERIMENTAL!!!
NOT YET TESTED at all!!!
"""
"""EXPERIMENTAL!!!"""
def
__init__
(
self
,
*
parsers
:
Parser
,
mandatory
:
int
=
NO_MANDATORY
,
err_msgs
:
MessagesType
=
[],
skip
:
ResumeList
=
[],
repetitions
:
Sequence
[
Tuple
[
int
,
int
]]
=
())
->
None
:
assert
len
(
set
(
parsers
))
==
len
(
parsers
)
assert
all
(
not
isinstance
(
parser
,
Option
)
and
not
isinstance
(
parser
,
OneOrMore
)
and
not
isinstance
(
parser
,
FlowParser
)
for
parser
in
parsers
)
super
(
Interleave
,
self
).
__init__
(
...
...
@@ -2343,6 +2354,7 @@ class Interleave(MandatoryNary):
consumed
=
set
()
# type: Set[Parser]
error
=
None
# type: Optional[Error]
while
True
:
# there is an order of testing, but no promise about the order of testing, here!
for
i
,
parser
in
enumerate
(
self
.
parsers
):
if
parser
not
in
consumed
:
node
,
text__
=
parser
(
text_
)
...
...
@@ -2379,6 +2391,46 @@ class Interleave(MandatoryNary):
def
__repr__
(
self
):
return
' ° '
.
join
(
parser
.
repr
for
parser
in
self
.
parsers
)
def
_prepare_combined
(
self
,
other
:
Parser
)
->
Tuple
[
Tuple
[
Parser
],
int
,
List
[
Tuple
[
int
,
int
]]]:
"""Returns the other's parsers and repetitions if `other` is an Interleave-parser,
otherwise returns ((other,),), [(1, 1])."""
other_parsers
=
cast
(
'Interleave'
,
other
).
parsers
if
isinstance
(
other
,
Interleave
)
\
else
cast
(
Tuple
[
Parser
,
...],
(
other
,))
# type: Tuple[Parser, ...]
other_repetitions
=
cast
(
'Interleave'
,
other
).
repetitions
\
if
isinstance
(
other
,
Interleave
)
else
[(
1
,
1
),]
other_mandatory
=
cast
(
'Interleave'
,
other
).
mandatory
\
if
isinstance
(
other
,
Interleave
)
else
NO_MANDATORY
if
other_mandatory
==
NO_MANDATORY
:
mandatory
=
self
.
mandatory
parsers
=
self
.
parsers
+
other_parsers
repetitions
=
self
.
repetitions
+
other_repetitions
elif
self
.
mandatory
==
NO_MANDATORY
:
mandatory
=
other_mandatory
parsers
=
other_parsers
+
self
.
parsers
repetitions
=
other_repetitions
+
self
.
repetitions
else
:
mandatory
=
self
.
mandatory
+
other_mandatory
parsers
=
self
.
parsers
[:
self
.
mandatory
]
+
other_parsers
[:
other_mandatory
]
\
+
self
.
parsers
[
self
.
mandatory
:]
+
other_parsers
[
other_mandatory
:]
repetitions
=
self
.
repetitions
[:
self
.
mandatory
]
+
other_repetitions
[:
other_mandatory
]
\
+
self
.
repetitions
[
self
.
mandatory
:]
+
other_repetitions
[
other_mandatory
:]
return
parsers
,
mandatory
,
repetitions
def
__mul__
(
self
,
other
:
Parser
)
->
'Interleave'
:
parsers
,
mandatory
,
repetitions
=
self
.
_prepare_combined
(
other
)
return
Interleave
(
*
parsers
,
mandatory
=
mandatory
,
repetitions
=
repetitions
)
def
__rmul__
(
self
,
other
:
Parser
)
->
'Interleave'
:
parsers
,
mandatory
,
repetitions
=
self
.
_prepare_combined
(
other
)
return
Interleave
(
*
parsers
,
mandatory
=
mandatory
,
repetitions
=
repetitions
)
def
__imul__
(
self
,
other
:
Parser
)
->
'Interleave'
:
parsers
,
mandatory
,
repetitions
=
self
.
_prepare_combined
(
other
)
self
.
parsers
=
parsers
self
.
mandatory
=
mandatory
self
.
repetitions
=
repetitions
return
self
########################################################################
#
...
...
test/test_parse.py
View file @
1c999dbb
...
...
@@ -1122,6 +1122,55 @@ class TestMetaParser:
assert
bool
(
cst
.
pick
(
'MUL'
)),
"Named empty nodes should not be dropped!!!"
class
TestParserCombining
:
def
test_series
(
self
):
parser
=
RegExp
(
r
'\d+'
)
+
RegExp
(
r
'\.'
)
assert
isinstance
(
parser
,
Series
)
parser
+=
RegExp
(
r
'\d+'
)
assert
isinstance
(
parser
,
Series
)
assert
len
(
parser
.
parsers
)
==
3
parser
=
Token
(
">"
)
+
parser
assert
isinstance
(
parser
,
Series
)
assert
len
(
parser
.
parsers
)
==
4
parser
=
parser
+
Token
(
"<"
)
assert
isinstance
(
parser
,
Series
)
assert
len
(
parser
.
parsers
)
==
5
def
test_alternative
(
self
):
parser
=
RegExp
(
r
'\d+'
)
|
RegExp
(
r
'\.'
)
assert
isinstance
(
parser
,
Alternative
)
parser
|=
RegExp
(
r
'\d+'
)
assert
isinstance
(
parser
,
Alternative
)
assert
len
(
parser
.
parsers
)
==
3
parser
=
Token
(
">"
)
|
parser
assert
isinstance
(
parser
,
Alternative
)
assert
len
(
parser
.
parsers
)
==
4
parser
=
parser
|
Token
(
"<"
)
assert
isinstance
(
parser
,
Alternative
)
assert
len
(
parser
.
parsers
)
==
5
def
test_interleave
(
self
):
parser
=
RegExp
(
r
'\d+'
)
*
RegExp
(
r
'\.'
)
assert
isinstance
(
parser
,
Interleave
)
parser
*=
RegExp
(
r
'\d+'
)
assert
isinstance
(
parser
,
Interleave
)
assert
len
(
parser
.
parsers
)
==
3
parser
=
Token
(
">"
)
*
parser
assert
isinstance
(
parser
,
Interleave
)
assert
len
(
parser
.
parsers
)
==
4
parser
=
parser
*
Token
(
"<"
)
assert
isinstance
(
parser
,
Interleave
)
assert
len
(
parser
.
parsers
)
==
5
def
test_mixed_combinations
(
self
):
parser
=
RegExp
(
r
'\d+'
)
+
RegExp
(
r
'\.'
)
+
RegExp
(
r
'\d+'
)
|
RegExp
(
r
'\d+'
)
assert
isinstance
(
parser
,
Alternative
)
assert
len
(
parser
.
parsers
)
==
2
assert
isinstance
(
parser
.
parsers
[
0
],
Series
)
assert
len
(
parser
.
parsers
[
0
].
parsers
)
==
3
assert
isinstance
(
parser
.
parsers
[
1
],
RegExp
)
if
__name__
==
"__main__"
:
from
DHParser.testing
import
runner
runner
(
""
,
globals
())
Write
Preview
Supports
Markdown
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