Castle: The best Real-Time/Embedded/HighTech language EVER. Attempt 2
Révision | 68702f02a7efd0206dfc5aa3f4829135969924f9 (tree) |
---|---|
l'heure | 2022-02-26 07:39:53 |
Auteur | Albert Mietus < albert AT mietus DOT nl > |
Commiter | Albert Mietus < albert AT mietus DOT nl > |
AST2XML:: Added Grammar-ast/class/xml; needed to refactor/rewrite the peg.Grammar inerface; to store the order. Adappted some tests
@@ -111,21 +111,7 @@ | ||
111 | 111 | self._ast2xml(ast.name, setting) |
112 | 112 | self._ast2xml(ast.value, setting) |
113 | 113 | |
114 | - | |
115 | - | |
116 | -############# | |
117 | - | |
118 | - | |
119 | -## logger.debug(f"Setting2xml:: ast[{len(ast)}]") | |
120 | -## ET.SubElement(parent, 'Setting', name=ast.name, value=ast.value) | |
114 | + def Grammar2xml(self, ast, parent) ->None: | |
115 | + g = ET.SubElement(parent, 'Grammar', no_parse_rules=str(len(ast.parse_rules)), no_settings=str(len(ast.settings))) | |
116 | + self._ast2xml(ast._all_rules, g) | |
121 | 117 | |
122 | -## def Settings2xml(self, ast, parent) ->None: ... | |
123 | -# def Grammar2xml(self, ast, parent) ->None: ... | |
124 | - | |
125 | - | |
126 | - | |
127 | - | |
128 | - | |
129 | -# def NotPredicate2xml(self, ast, parent) ->None: ... | |
130 | - | |
131 | - |
@@ -2,6 +2,7 @@ | ||
2 | 2 | |
3 | 3 | from ._base import AST_BASE, ID, IDError |
4 | 4 | |
5 | +import typing | |
5 | 6 | |
6 | 7 | class PEG (AST_BASE): # abstract |
7 | 8 | """Base class of all PEG classes""" |
@@ -103,13 +104,13 @@ | ||
103 | 104 | |
104 | 105 | class Grammar(NonTerminal): |
105 | 106 | def __init__(self, *, |
106 | - rules: ParseRules=None, | |
107 | - settings: Settings=None, | |
107 | + all_rules: typing.Sequence[Rule], | |
108 | 108 | **kwargs): |
109 | - logger.debug(f'{self._typeName(self)}:: rules={rules}; settings={settings}, kwargs={kwargs}') | |
110 | 109 | super().__init__(**kwargs) |
111 | - self.rules = rules | |
112 | - self.settings = settings | |
110 | + self._all_rules = Rules(children=all_rules) # store `all_rules` in once, to be able to remember the order | |
111 | + self.parse_rules = ParseRules( children=[r for r in self._all_rules if isinstance(r, Rule)] ) | |
112 | + self.settings = Settings( children=[r for r in self._all_rules if isinstance(r, Setting)] ) | |
113 | + assert len(all_rules) == len(self.parse_rules) + len(self.settings) | |
113 | 114 | |
114 | 115 | |
115 | 116 | class Group(Expression): pass # abstract -- Note: Do not Group for '(' ...')'; that's a Sequence!! |
@@ -117,13 +117,7 @@ | ||
117 | 117 | |
118 | 118 | |
119 | 119 | def visit_peg_grammar(self, node, children): |
120 | - rules=children[0] | |
121 | - logger.debug('visit_peg_grammar::' + self._logstr_node_children(node, children) + f'rules:: {rules}') | |
122 | - parse_rules = peg.ParseRules( children=[r for r in rules if isinstance(r, peg.Rule)] ) | |
123 | - settings = peg.Settings( children=[r for r in rules if isinstance(r, peg.Setting)] ) | |
124 | - assert len(rules) == len(parse_rules) + len(settings), f'Number of parse_rules ({len(parse_rules)}) and settings ({len(settings)}), does not match total: {len(rules)}' | |
125 | - return peg.Grammar(rules=parse_rules, settings=settings, parse_tree=node) | |
126 | - | |
120 | + return peg.Grammar(all_rules=children[0], parse_tree=node) | |
127 | 121 | |
128 | 122 | def visit_setting_name(self, node, children): |
129 | 123 | return peg.ID(name=str(node), parse_tree=node) |
@@ -0,0 +1,39 @@ | ||
1 | +import pytest | |
2 | +import logging; logger = logging.getLogger(__name__) | |
3 | + | |
4 | +from castle.ast import peg | |
5 | + | |
6 | +from . import xml_serialize #@pytest.fixture | |
7 | +from . import assert_xml_Element, StdSequence_withAsserts | |
8 | + | |
9 | +def test_a_Grammar_with_ParseRules_only(xml_serialize): | |
10 | + name1, seq1 = 'aParseRule', StdSequence_withAsserts() | |
11 | + name2, seq2 = 'rule_2', StdSequence_withAsserts() | |
12 | + r1 = peg.Rule(name=peg.ID(name=name1), expr=seq1.seq) | |
13 | + r2 = peg.Rule(name=peg.ID(name=name2), expr=seq2.seq) | |
14 | + | |
15 | + g = peg.Grammar(all_rules=(r1,r2)) | |
16 | + txt = xml_serialize(g) | |
17 | + logger.debug(f'XML:: {txt}') | |
18 | + | |
19 | + assert_xml_Element(txt, tag='Grammar', child_count=2) | |
20 | + assert_xml_Element(txt, tag='Grammar/Rule[1]', name=name1) | |
21 | + assert_xml_Element(txt, tag='Grammar/Rule[2]', name=name2) | |
22 | + | |
23 | +def test_a_Grammar_with_MixedRules(xml_serialize): | |
24 | + name1, seq1 = 'aParseRule', StdSequence_withAsserts() | |
25 | + name2, val2 = 'setting2', "1965" | |
26 | + name3, seq3 = 'rule_3', StdSequence_withAsserts() | |
27 | + r1 = peg.Rule(name=peg.ID(name=name1), expr=seq1.seq) | |
28 | + r2 = peg.Setting(name=peg.ID(name=name2), value=peg.Number(value=val2)) | |
29 | + r3 = peg.Rule(name=peg.ID(name=name3), expr=seq3.seq) | |
30 | + | |
31 | + g = peg.Grammar(all_rules=(r1,r2,r3)) | |
32 | + txt = xml_serialize(g) | |
33 | + logger.debug(f'XML:: {txt}') | |
34 | + | |
35 | + assert_xml_Element(txt, tag='Grammar', child_count=3) | |
36 | + assert_xml_Element(txt, tag='Grammar/Rule[1]', name=name1) | |
37 | + assert_xml_Element(txt, tag='Grammar/Setting/ID', name=name2) | |
38 | + assert_xml_Element(txt, tag='Grammar/Rule[2]', name=name3) | |
39 | + |
@@ -61,7 +61,7 @@ | ||
61 | 61 | def assert_PEG(ast, *, no_of_rules=None, no_of_settings=None): |
62 | 62 | assert isinstance(ast, peg.Grammar) |
63 | 63 | |
64 | - rules = ast.rules | |
64 | + rules = ast.parse_rules | |
65 | 65 | assert isinstance(rules, peg.Rules) |
66 | 66 | if no_of_rules: |
67 | 67 | assert len(rules) == no_of_rules, f"The number of (parse_)rules ({len(rules)}) does not match the spec: {no_of_rules}" |