Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
A
arpeggio-gm
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
backend
arpeggio-gm
Commits
d5c9fa47
Commit
d5c9fa47
authored
Aug 04, 2014
by
Igor Dejanovic
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Parse tree navigation using dot syntax + unit tests.
parent
6f1c305e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
102 additions
and
46 deletions
+102
-46
__init__.py
arpeggio/__init__.py
+39
-16
test_ptnode_navigation_expressions.py
tests/unit/test_ptnode_navigation_expressions.py
+63
-0
test_rulename_lookup.py
tests/unit/test_rulename_lookup.py
+0
-30
No files found.
arpeggio/__init__.py
View file @
d5c9fa47
...
...
@@ -677,50 +677,73 @@ class Terminal(ParseTreeNode):
class
NonTerminal
(
ParseTreeNode
,
list
):
"""
Non-leaf node of the Parse Tree. Represents language syntax construction.
At the same time used in ParseTreeNode navigation expressions.
See test_ptnode_navigation_expressions.py for examples of navigation expressions.
Attributes:
nodes (list of ParseTreeNode): Children parse tree nodes.
_filtered (bool): Is this NT a dynamically created filtered NT.
This is used internally.
"""
def
__init__
(
self
,
rule
,
position
,
nodes
,
error
=
False
):
def
__init__
(
self
,
rule
,
position
,
nodes
,
error
=
False
,
_filtered
=
False
):
super
(
NonTerminal
,
self
)
.
__init__
(
rule
,
position
,
error
)
self
.
extend
(
flatten
([
nodes
]))
self
.
_filtered
=
_filtered
# Child nodes cache. Used for lookup by rule name.
self
.
_child_cache
=
{}
# Navigation expression cache. Used for lookup by rule name.
self
.
_expr_cache
=
{}
@property
def
value
(
self
):
"""Terminal protocol."""
return
str
(
self
)
@property
def
desc
(
self
):
return
self
.
name
# def __iter__(self):
# return self
def
__str__
(
self
):
return
" | "
.
join
([
str
(
x
)
for
x
in
self
])
def
__repr__
(
self
):
return
"[
%
s ]"
%
", "
.
join
([
repr
(
x
)
for
x
in
self
])
def
__getattr__
(
self
,
item
):
def
__getattr__
(
self
,
rule_name
):
"""
Find a child (non)terminal by the rule name.
Args:
item(str): The name of the child node.
rule_name(str): The name of the rule that is referenced from
this node rule.
"""
# Prevent infinite recursion
if
rule_name
==
'_expr_cache'
:
raise
AttributeError
# First check the cache
if
item
in
self
.
_child
_cache
:
return
self
.
_
child_cache
[
item
]
if
rule_name
in
self
.
_expr
_cache
:
return
self
.
_
expr_cache
[
rule_name
]
# If not found in the cache find it and store it in the
# cache for later.
# If result is not found in the cache collect all nodes
# with the given rule name and create new NonTerminal
# and cache it for later access.
nodes
=
[]
for
n
in
self
:
if
n
.
rule
==
item
:
self
.
_child_cache
[
item
]
=
n
return
n
if
self
.
_filtered
:
# For filtered NT rule_name is a rule on
# each of its children
for
m
in
n
:
if
m
.
rule
==
rule_name
:
nodes
.
append
(
m
)
else
:
if
n
.
rule
==
rule_name
:
nodes
.
append
(
n
)
raise
AttributeError
# For expression NonTerminals instances position does not have any sense.
result
=
NonTerminal
(
rule
=
rule_name
,
position
=
None
,
nodes
=
nodes
,
_filtered
=
True
)
self
.
_expr_cache
[
rule_name
]
=
result
return
result
# ----------------------------------------------------
...
...
tests/unit/test_ptnode_navigation_expressions.py
0 → 100644
View file @
d5c9fa47
# -*- coding: utf-8 -*-
#######################################################################
# Name: test_ptnode_navigation_expressions
# Purpose: Test ParseTreeNode navigation expressions.
# Author: Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com>
# Copyright: (c) 2014 Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com>
# License: MIT License
#######################################################################
import
pytest
# Grammar
from
arpeggio
import
ParserPython
,
ZeroOrMore
,
ParseTreeNode
,
NonTerminal
from
arpeggio.export
import
PTDOTExporter
def
foo
():
return
"a"
,
bar
,
"b"
,
baz
,
bar2
,
ZeroOrMore
(
bar
)
def
bar
():
return
[
bla
,
bum
],
baz
,
"c"
def
bar2
():
return
ZeroOrMore
(
bla
)
def
baz
():
return
"d"
def
bla
():
return
"bla"
def
bum
():
return
[
"bum"
,
"bam"
]
def
test_lookup_single
():
parser
=
ParserPython
(
foo
,
reduce_tree
=
False
)
result
=
parser
.
parse
(
"a bum d c b d bla bum d c"
)
# Uncomment following line to visualize the parse tree in graphviz
# PTDOTExporter().exportFile(result, 'test_ptnode_navigation_expressions.dot')
assert
isinstance
(
result
,
ParseTreeNode
)
assert
isinstance
(
result
.
bar
,
NonTerminal
)
# dot access
assert
result
.
bar
.
rule
==
'bar'
# Index access
assert
result
[
1
]
.
rule
==
'bar'
# There are six children from result
assert
len
(
result
)
==
6
# There is two bar matched from result (at the begging and from ZeroOrMore)
# Dot access collect all NTs from the given path
assert
len
(
result
.
bar
)
==
2
# Verify position
assert
result
.
bar
[
0
]
.
position
==
2
assert
result
.
bar
[
1
]
.
position
==
18
# Multilevel dot access returns all elements from all previous ones.
# For example this returns all bum from all bar in result
assert
len
(
result
.
bar
.
bum
)
==
2
# Verify that proper bum are returned
assert
result
.
bar
.
bum
[
0
]
.
rule
==
'bum'
assert
result
.
bar
.
bum
[
1
]
.
position
==
18
# The same for all bla from all bar2
assert
len
(
result
.
bar2
.
bla
)
==
1
assert
hasattr
(
result
,
"bar"
)
assert
hasattr
(
result
,
"baz"
)
tests/unit/test_rulename_lookup.py
deleted
100644 → 0
View file @
6f1c305e
# -*- coding: utf-8 -*-
#######################################################################
# Name: test_peg_parser
# Purpose: Test for parser constructed using PEG textual grammars.
# Author: Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com>
# Copyright: (c) 2014 Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com>
# License: MIT License
#######################################################################
import
pytest
# Grammar
from
arpeggio
import
ParserPython
,
ZeroOrMore
def
foo
():
return
"a"
,
bar
,
"b"
,
baz
def
bar
():
return
"c"
def
baz
():
return
"d"
def
test_lookup_single
():
parser
=
ParserPython
(
foo
)
result
=
parser
.
parse
(
"a c b d"
)
assert
hasattr
(
result
,
"bar"
)
assert
hasattr
(
result
,
"baz"
)
assert
not
hasattr
(
result
,
"unexisting"
)
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