Skip to content

Commit a1a9199

Browse files
authored
Merge pull request #105 from Pennycook/tree-walk
Add tree walk function
2 parents 6910106 + b8ce120 commit a1a9199

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

codebasin/preprocessor.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
import hashlib
1212
import logging
1313
import os
14+
from collections.abc import Iterable
1415
from copy import copy
16+
from typing import Self
1517

1618
import numpy as np
1719

@@ -583,6 +585,18 @@ def evaluate_for_platform(self, **kwargs):
583585
"""
584586
return False
585587

588+
def walk(self) -> Iterable[Self]:
589+
"""
590+
Returns
591+
-------
592+
Iterable[Self]
593+
An Iterable visiting all descendants of this node via a preorder
594+
traversal.
595+
"""
596+
yield self
597+
for child in self.children:
598+
yield from child.walk()
599+
586600

587601
class FileNode(Node):
588602
"""
@@ -2330,6 +2344,16 @@ def __init__(self, filename):
23302344
self.root = FileNode(filename)
23312345
self._latest_node = self.root
23322346

2347+
def walk(self) -> Iterable[Node]:
2348+
"""
2349+
Returns
2350+
-------
2351+
Iterable[Node]
2352+
An Iterable visiting all nodes in the tree via a preorder
2353+
traversal.
2354+
"""
2355+
yield from self.root.walk()
2356+
23332357
def associate_file(self, filename):
23342358
self.root.filename = filename
23352359

tests/source-tree/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Copyright (C) 2019-2024 Intel Corporation
2+
# SPDX-License-Identifier: BSD-3-Clause

tests/source-tree/test_source_tree.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Copyright (C) 2019-2024 Intel Corporation
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
import logging
5+
import tempfile
6+
import unittest
7+
import warnings
8+
9+
from codebasin.file_parser import FileParser
10+
from codebasin.preprocessor import CodeNode, DirectiveNode, FileNode
11+
12+
13+
class TestSourceTree(unittest.TestCase):
14+
"""
15+
Test SourceTree class.
16+
"""
17+
18+
def setUp(self):
19+
logging.getLogger("codebasin").disabled = False
20+
warnings.simplefilter("ignore", ResourceWarning)
21+
22+
def test_walk(self):
23+
"""Check that walk() visits nodes in the expected order"""
24+
25+
# TODO: Revisit this when SourceTree can be built without a file.
26+
with tempfile.NamedTemporaryFile(
27+
mode="w",
28+
delete_on_close=False,
29+
suffix=".cpp",
30+
) as f:
31+
source = """
32+
#if defined(FOO)
33+
void foo();
34+
#elif defined(BAR)
35+
void bar();
36+
#else
37+
void baz();
38+
#endif
39+
40+
void qux();
41+
"""
42+
f.write(source)
43+
f.close()
44+
45+
# TODO: Revisit this when __str__() is more reliable.
46+
tree = FileParser(f.name).parse_file(summarize_only=False)
47+
expected_types = [
48+
FileNode,
49+
DirectiveNode,
50+
CodeNode,
51+
DirectiveNode,
52+
CodeNode,
53+
DirectiveNode,
54+
CodeNode,
55+
DirectiveNode,
56+
CodeNode,
57+
]
58+
expected_contents = [
59+
f.name,
60+
"FOO",
61+
"foo",
62+
"BAR",
63+
"bar",
64+
"else",
65+
"baz",
66+
"endif",
67+
"qux",
68+
]
69+
for i, node in enumerate(tree.walk()):
70+
self.assertTrue(isinstance(node, expected_types[i]))
71+
if isinstance(node, CodeNode):
72+
contents = node.spelling()[0]
73+
else:
74+
contents = str(node)
75+
self.assertTrue(expected_contents[i] in contents)
76+
77+
78+
if __name__ == "__main__":
79+
unittest.main()

0 commit comments

Comments
 (0)