Coverage for lobster/tools/trlc/conversion_rule_lookup.py: 100%
27 statements
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-27 13:02 +0000
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-27 13:02 +0000
1from typing import Dict, Iterable
2from trlc import ast
4from lobster.tools.trlc.conversion_rule import ConversionRule
5from lobster.tools.trlc.hierarchy_tree import HierarchyTree
8def build_record_type_to_conversion_rule_lookup(
9 conversion_rules: Iterable[ConversionRule],
10 children_lookup: HierarchyTree,
11 symbol_table: ast.Symbol_Table,
12) -> Dict[ast.Record_Type, ConversionRule]:
13 """Iterates over all TRLC record types and generates a lookup dictionary
14 that also propagates conversion rules to derived record types (depending
15 on the value of ConversionRule.applies_to_derived_types).
17 That is, derived types can be looked up, too, and will return the
18 conversion rule of their parent type.
19 If a specific conversion rule is defined for a derived type, then the order
20 of the rules in the input list does not matter.
21 Only the order of the record types in the symbol table matters.
22 TRLC preserves the order of record types as found in the *.rsl files.
24 Example:
25 *.rsl defines these types in the given order:
26 type Level1 {}
27 type Level2 extends Level1 {}
29 Then any record object of Level2 will be converted using the
30 conversion rule for Level1, unless there is a specific conversion rule
31 for Level2 in the input list of conversion rules.
33 Note: The ConversionRule instance specifies only the record type name and
34 namespace, but not the concrete record type instance. That's why we need this
35 function after all.
36 This function searches for the concrete record type instance in the symbol table,
37 and then builds a lookup between the record types and their conversion rules.
39 If 'conversion_rules' contains a rule for a record type that is not
40 present in the symbol table, then that rule is ignored.
41 """
42 result = {}
43 # build temporary lookup based on fully qualified name of record type:
44 temporary_lookup = {(rule.package_name, rule.type_name): rule
45 for rule in conversion_rules}
46 # iterate over all record types in the symbol table
47 # and build the final lookup:
48 for record_type in get_record_types(symbol_table):
49 fully_qualified_name = (record_type.n_package.name, record_type.name)
50 rule = temporary_lookup.get(fully_qualified_name)
51 if rule:
52 result[record_type] = rule
53 if rule.applies_to_derived_types:
54 _propagate_rule_to_derived_types_recursively(
55 parent_extraction_rule=result[record_type],
56 parent_record_type=record_type,
57 children_lookup=children_lookup,
58 extraction_rules_lookup=result,
59 )
60 return result
63def _propagate_rule_to_derived_types_recursively(
64 parent_extraction_rule: ConversionRule,
65 parent_record_type: ast.Record_Type,
66 children_lookup: HierarchyTree,
67 extraction_rules_lookup: Dict[ast.Record_Type, ConversionRule]
68):
69 child_types = children_lookup.get(parent_record_type)
70 if child_types:
71 for child_type in child_types:
72 extraction_rules_lookup[child_type] = parent_extraction_rule
73 _propagate_rule_to_derived_types_recursively(
74 parent_extraction_rule,
75 child_type,
76 children_lookup,
77 extraction_rules_lookup,
78 )
81def get_record_types(symbol_table: ast.Symbol_Table) -> Iterable[ast.Record_Type]:
82 """Returns an iterable of all record types in the TRLC symbol table
83 while preserving the order.
84 """
86 # Note: The intuitive way to get all record types is to iterate like this:
87 # for n_pkg in symbol_table.values(ast.Package):
88 # yield from n_pkg.symbols.values(ast.Record_Type)
89 # Unfortunately the "ast.Symbol_Table.values" function returns the symbols in an
90 # alphabetically sorted order!
91 # So we have to implement our own iteration to preserve the order
93 for n_pkg in symbol_table.values(ast.Package):
94 table = n_pkg.symbols.table
95 for value in table.values():
96 if isinstance(value, ast.Record_Type):
97 yield value