Skip to content

Commit

Permalink
Iteration api by section (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
mugdhadhole1 authored Oct 14, 2024
1 parent 1461bd9 commit f4a647c
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 23 deletions.
11 changes: 6 additions & 5 deletions index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ Most likely that is enough, but you can access the entire parse tree
from this API.

.. toctree::
:maxdepth: 2
:caption: TRLC API Docs
:maxdepth: 2
:caption: TRLC API Docs

manual/infrastructure
manual/errors
manual/ast
manual/infrastructure
manual/errors
manual/ast
manual/section_api
38 changes: 38 additions & 0 deletions manual/section_api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Iteration API by section
=============================

This is description for the end-user facing TRLC iteration API by section

Function iter_record_objects_by_section() will yield
all the information about record objects, sections and file locations::

def iter_record_objects_by_section(self):

You need to input trlc files with requirements which contain
sections or nested sections with record objects::

# Iterates over each record object in the trlc files
# and yields the file location of trlc files
for record_object in self.iter_record_objects():
file_name = record_object.location.file_name
if location not in self.trlc_files:
self.trlc_files.append(location)
yield location

# This code block checks section, if present
# it will yield the section and level of section,
# record object and level of record object
if record_object.section:
object_level = len(record_object.section) - 1
for level, section in enumerate(record_object.section):
if section not in self.section_names:
self.section_names.append(section)
yield section.name, level
yield record_object, object_level

# If section is not present
# then it will yield the record object and level of record object
else:
object_level = 0
yield record_object, object_level

40 changes: 40 additions & 0 deletions tests-unit/test_ast_bysection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import unittest
from unittest.mock import patch, MagicMock
from trlc.ast import Symbol_Table

class TestRecordObject:
def __init__(self, location, section):
self.location = location
self.section = section

class TestSection:
def __init__(self, name):
self.name = name

class TestIterRecordObjectsBySection(unittest.TestCase):

@patch("trlc.ast.Symbol_Table.iter_record_objects")
def test_iter_record_objects_by_section(self, mock_iter_record_objects):
mock_location1 = MagicMock(file_name = 'file1')
mock_section1 = TestSection('section1')
mock_section2 = TestSection('section2')
mock_location2 = MagicMock(file_name = 'file2')
record1 = TestRecordObject(mock_location1, [mock_section1, mock_section2])
record2 = TestRecordObject(mock_location2, [])
mock_iter_record_objects.return_value = [record1, record2]

results = list(Symbol_Table().iter_record_objects_by_section())

expected_results = [
'file1',
('section1', 0),
('section2', 1),
(record1, 1),
'file2',
(record2, 0)
]

self.assertEqual(results, expected_results)

if __name__ == '__main__':
unittest.main()
15 changes: 9 additions & 6 deletions trlc-lrm-generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -812,8 +812,8 @@ def write_text_object(fd, mh, obj, context, bnf_parser):

# Build current section
if obj.section:
new_section = section_list(obj.section)
new_hashes = section_hashes(obj.section)
new_section = section_list(obj.section[-1])
new_hashes = section_hashes(obj.section[-1])
else:
new_section = []

Expand Down Expand Up @@ -1198,14 +1198,17 @@ def write_toc(fd, pkg_lrm):

old_section = None
for obj in pkg_lrm.symbols.iter_record_objects():
if not obj.section:
if obj.section is None:
continue
if old_section == obj.section:
obj_section = obj.section[-1]
if not obj_section:
continue
old_section = obj.section
if old_section == obj_section:
continue
old_section = obj_section

sections = []
ptr = obj.section
ptr = obj_section
while ptr:
sections = [ptr] + sections
ptr = ptr.parent
Expand Down
33 changes: 30 additions & 3 deletions trlc/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -2944,7 +2944,7 @@ def __init__(self, name, location, n_typ, section, n_package):
# lobster-trace: LRM.Record_Object_Declaration

assert isinstance(n_typ, Record_Type)
assert isinstance(section, Section) or section is None
assert isinstance(section, list) or section is None
assert isinstance(n_package, Package)
super().__init__(name, location, n_typ)
self.field = {
Expand Down Expand Up @@ -2997,7 +2997,7 @@ def dump(self, indent=0): # pragma: no cover
self.write_indent(indent + 1, "Field %s" % key)
value.dump(indent + 2)
if self.section:
self.section.dump(indent + 1)
self.section[-1].dump(indent + 1)

def resolve_references(self, mh):
assert isinstance(mh, Message_Handler)
Expand Down Expand Up @@ -3052,7 +3052,7 @@ class Section(Entity):
def __init__(self, name, location, parent):
super().__init__(name, location)
assert isinstance(parent, Section) or parent is None
self.parent = parent
self.parent = parent

def dump(self, indent=0): # pragma: no cover
self.write_indent(indent, "Section %s" % self.name)
Expand All @@ -3075,6 +3075,8 @@ def __init__(self, parent=None):
self.parent = parent
self.imported = []
self.table = OrderedDict()
self.trlc_files = []
self.section_names = []

@staticmethod
def simplified_name(name):
Expand All @@ -3093,6 +3095,31 @@ def all_names(self):
rv |= self.parent.all_names()
return rv

def iter_record_objects_by_section(self):
"""API for users
Retriving information about the section hierarchy for record objects
Inputs: folder with trlc files where trlc files have sections,
sub sections and record objects
Output: Information about sections and level of sections,
record objects and levels of record object
"""
for record_object in self.iter_record_objects():
location = record_object.location.file_name
if location not in self.trlc_files:
self.trlc_files.append(location)
yield location
if record_object.section:
object_level = len(record_object.section) - 1
for level, section in enumerate(record_object.section):
if section not in self.section_names:
self.section_names.append(section)
yield section.name, level
yield record_object, object_level
else:
object_level = 0
yield record_object, object_level

def iter_record_objects(self):
# lobster-exclude: API for users
""" Iterate over all record objects
Expand Down
13 changes: 4 additions & 9 deletions trlc/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1539,14 +1539,9 @@ def parse_section_declaration(self):
self.match_kw("section")
t_section = self.ct
self.match("STRING")
if self.section:
sec = ast.Section(name = self.ct.value,
location = self.ct.location,
parent = self.section[-1])
else:
sec = ast.Section(name = self.ct.value,
location = self.ct.location,
parent = None)
sec = ast.Section(name = self.ct.value,
location = self.ct.location,
parent = self.section[-1] if self.section else None)
sec.set_ast_link(self.ct)
sec.set_ast_link(t_section)
self.section.append(sec)
Expand Down Expand Up @@ -1792,7 +1787,7 @@ def parse_record_object_declaration(self):
name = self.ct.value,
location = self.ct.location,
n_typ = r_typ,
section = self.section[-1] if self.section else None,
section = self.section.copy() if self.section else None,
n_package = self.cu.package)
self.cu.package.symbols.register(self.mh, obj)
obj.set_ast_link(self.ct)
Expand Down

0 comments on commit f4a647c

Please sign in to comment.