Castle: The best Real-Time/Embedded/HighTech language EVER. Attempt 2
修訂 | b7dd492c2c77fcae68e6a5668eb1d5a841189628 (tree) |
---|---|
時間 | 2022-02-12 06:15:35 |
作者 | Albert Mietus < albert AT mietus DOT nl > |
Commiter | Albert Mietus < albert AT mietus DOT nl > |
AST-2-XML:: OrderedChoice (alternativies) works
@@ -81,6 +81,11 @@ | ||
81 | 81 | def ZeroOrMore2xml(self, ast, parent): self._quantity_op(ast, parent, 'ZeroOrMore') |
82 | 82 | def OneOrMore2xml(self, ast, parent): self._quantity_op(ast, parent, 'OneOrMore') |
83 | 83 | |
84 | + def OrderedChoice2xml(self, ast, parent) ->None: | |
85 | + oc = ET.SubElement(parent, 'OrderedChoice') | |
86 | + for c in ast: | |
87 | + self._ast2xml(c,oc) | |
88 | + | |
84 | 89 | ############# |
85 | 90 | |
86 | 91 | ## def Setting2xml(self, ast, parent) ->None: |
@@ -92,7 +97,7 @@ | ||
92 | 97 | |
93 | 98 | |
94 | 99 | |
95 | -# def OrderedChoice 2xml(self, ast, parent) ->None: ... | |
100 | + | |
96 | 101 | # def AndPredicate2xml(self, ast, parent) ->None: ... |
97 | 102 | # def NotPredicate2xml(self, ast, parent) ->None: ... |
98 | 103 |
@@ -17,7 +17,8 @@ | ||
17 | 17 | #NO_VISITOR_NEEDED: visit_term |
18 | 18 | #NO_VISITOR_NEEDED: visit_re_no_slash |
19 | 19 | #NO_VISITOR_NEEDED: visit_group |
20 | -#NO_VISITOR_NEEDED: visit_op_quantity -- handle in visit_single_expr | |
20 | +#NO_VISITOR_NEEDED: visit_op_quantity -- handled in visit_single_expr | |
21 | +#NO_VISITOR_NEEDED: visit_op_alternative -- handled in visit_expression | |
21 | 22 | |
22 | 23 | class PegVisitor(arpeggio.PTNodeVisitor): |
23 | 24 | def _logstr_node_children(self, node, children): |
@@ -64,19 +65,12 @@ | ||
64 | 65 | raise NotImplementedError("visit_single_expr, len>2") # XXX -- Is this possible? |
65 | 66 | |
66 | 67 | |
67 | - def visit_expression(self, node, children): # ( expressions, op_alternatives ) | |
68 | + def visit_expression(self, node, children): # expression <- expressionS, op_alternative; op_alternative <- ('|' expression)? | |
68 | 69 | logger.debug('visit_expression::' + self._logstr_node_children(node, children)) |
69 | 70 | if len(children) == 1: #Only expressions |
70 | 71 | return children[0] |
71 | - elif len(children) == 2: # So, having with alternatives | |
72 | - # The 1st kid is a peg.Sequence ``expr`` | |
73 | - # The 2nd kid can be a | |
74 | - # - peg.Sequence `` | expr ``, OR | |
75 | - # - peg.OrderedChoice `` | expr | expr`` | |
72 | + elif len(children) == 2: # So, having 1 or more alternatives in children[1] | |
76 | 73 | # In all cased a (single) OrderedChoice with a list of alternatives should be returned. |
77 | -# return peg.OrderedChoice(children = ((children[0].value,) + | |
78 | -# children[1]._childeren if isinstance(children[1], peg.OrderedChoice) else children[1].value), #XXX HACK | |
79 | -# parse_tree=node) | |
80 | 74 | if isinstance(children[1], peg.OrderedChoice): |
81 | 75 | alternatives = [children[0]] + [alt for alt in children[1]] |
82 | 76 | else: |
@@ -20,28 +20,32 @@ | ||
20 | 20 | assert_xml_Element(txt, tag='.//RegExpTerm', value=self.v3) |
21 | 21 | |
22 | 22 | |
23 | -def assert_xml_Element(txt, tag, | |
24 | - version="0.0", | |
25 | - **attribs,): | |
23 | +def assert_xml_Element(txt, tag, version="0.0", child_count=None, **attribs,): | |
26 | 24 | """Partially verify an xml-string; focusing on 'tag' -- a real tag, or a (limited) XPATH-expression. |
27 | 25 | |
28 | 26 | This `tag` (expression) should result in a single hit!. *Use e.g `[0]` as suffix to select one from a list*. |
29 | - Pass ``key=value`` **attribs** to verify the found tag has those attribs and values | |
30 | - """ | |
27 | + Pass ``key=value`` **attribs** to verify the found tag has those attribs and values.""" | |
31 | 28 | |
32 | 29 | tree = ET.fromstring(txt) |
33 | 30 | if version: |
34 | 31 | assert tree.attrib['version'] == version |
32 | + | |
35 | 33 | founds = tree.findall(tag) |
36 | 34 | assert len(founds) == 1, f"Expected only one element; got: {len(founds)} :{founds}" |
35 | + | |
37 | 36 | found = founds[0] |
38 | 37 | logger.debug(f'XXX1 tag={tag}:: found={found}') |
38 | + | |
39 | 39 | for attrib, value in attribs.items(): |
40 | 40 | logger.debug(f'XXX2 tag={tag}:: attrib={attrib}, value={value}') |
41 | 41 | assert found.attrib[attrib] == value |
42 | 42 | |
43 | + if child_count: | |
44 | + assert len(found) == child_count, f"The number of children of '{tag}' is {len(found)}, which does not match the specified child_count={child_count}" | |
43 | 45 | |
44 | -def assert_QuantityGroup(xml_serialize, pegGrp, tagName): | |
46 | + | |
47 | + | |
48 | +def verify_QuantityGroup(xml_serialize, pegGrp, tagName): | |
45 | 49 | seq = StdSequence_withAsserts() |
46 | 50 | txt = xml_serialize(pegGrp(expr=seq.seq)) |
47 | 51 | logger.debug(f'XML:: {txt}') |
@@ -49,7 +53,8 @@ | ||
49 | 53 | assert_xml_Element(txt, tagName) |
50 | 54 | seq.assert_xml_Element(txt) |
51 | 55 | |
52 | -def assert_QuantityID(xml_serialize, pegGrp, tagName, id_name='JustAName'): | |
56 | + | |
57 | +def verify_QuantityID(xml_serialize, pegGrp, tagName, id_name='JustAName'): | |
53 | 58 | txt = xml_serialize(pegGrp(expr=peg.ID(name=id_name))) |
54 | 59 | logger.debug(f'XML:: {txt}') |
55 | 60 |
@@ -4,7 +4,7 @@ | ||
4 | 4 | |
5 | 5 | from castle.ast import peg, serialization |
6 | 6 | |
7 | -from . import StdSequence_withAsserts, assert_xml_Element, assert_QuantityGroup, assert_QuantityID | |
7 | +from . import StdSequence_withAsserts, assert_xml_Element, verify_QuantityGroup, verify_QuantityID | |
8 | 8 | |
9 | 9 | |
10 | 10 | @pytest.fixture |
@@ -84,24 +84,29 @@ | ||
84 | 84 | assert tree.findall('.//Rule[2]//StrTerm')[0].attrib['value'] == 'str2' |
85 | 85 | |
86 | 86 | |
87 | -def test_OptionalSeq(xml_serialize): assert_QuantityGroup(xml_serialize, peg.Optional, 'Optional') ## ` ( ...)? ` | |
88 | -def test_ZeroOrMoreSeq(xml_serialize): assert_QuantityGroup(xml_serialize, peg.ZeroOrMore, 'ZeroOrMore') ## ` ( ...)* ` | |
89 | -def test_OneOrMoreSeq(xml_serialize): assert_QuantityGroup(xml_serialize, peg.OneOrMore, 'OneOrMore') ## ` ( ...)+ ` | |
90 | -def test_UnorderedGroup(xml_serialize): assert_QuantityGroup(xml_serialize, peg.UnorderedGroup, 'UnorderedGroup') ## ` ( ...)# ` # Only useful for a group/sequence!! | |
87 | +def test_OptionalSeq(xml_serialize): verify_QuantityGroup(xml_serialize, peg.Optional, 'Optional') ## ` ( ...)? ` | |
88 | +def test_ZeroOrMoreSeq(xml_serialize): verify_QuantityGroup(xml_serialize, peg.ZeroOrMore, 'ZeroOrMore') ## ` ( ...)* ` | |
89 | +def test_OneOrMoreSeq(xml_serialize): verify_QuantityGroup(xml_serialize, peg.OneOrMore, 'OneOrMore') ## ` ( ...)+ ` | |
90 | +def test_UnorderedGroup(xml_serialize): verify_QuantityGroup(xml_serialize, peg.UnorderedGroup, 'UnorderedGroup') ## ` ( ...)# ` # Only useful for a group/sequence!! | |
91 | + | |
92 | +def test_OptionalID(xml_serialize): verify_QuantityID(xml_serialize, peg.Optional, 'Optional') | |
93 | +def test_ZeroOrMoreID(xml_serialize): verify_QuantityID(xml_serialize, peg.ZeroOrMore, 'ZeroOrMore') | |
94 | +def test_OneOrMoreID(xml_serialize): verify_QuantityID(xml_serialize, peg.OneOrMore, 'OneOrMore') | |
95 | +def test_UnorderedID(xml_serialize): verify_QuantityID(xml_serialize, peg.UnorderedGroup, 'UnorderedGroup', 'strange') ## A bit uncommon: an unordered group of ONE! But it should work. | |
91 | 96 | |
92 | 97 | |
93 | -def test_OptionalID(xml_serialize): assert_QuantityID(xml_serialize, peg.Optional, 'Optional') | |
94 | -def test_ZeroOrMoreID(xml_serialize): assert_QuantityID(xml_serialize, peg.ZeroOrMore, 'ZeroOrMore') | |
95 | -def test_OneOrMoreID(xml_serialize): assert_QuantityID(xml_serialize, peg.OneOrMore, 'OneOrMore') | |
96 | -## A bit uncommon: unordered group of ONE :`` Always#`` but it should work | |
97 | -def test_UnorderedID(xml_serialize): assert_QuantityID(xml_serialize, peg.UnorderedGroup, 'UnorderedGroup', 'strange') | |
98 | +def test_OC3(xml_serialize): # e1 | e2 | e2 | |
99 | + e1, e2, e3 = peg.ID(name='ID_1'), peg.StrTerm(value='str_2'), peg.RegExpTerm(value='regexp_3') | |
100 | + txt = xml_serialize(peg.OrderedChoice(children=[e1,e2,e3])) | |
101 | + logger.debug(f'XML:: {txt}') | |
102 | + | |
103 | + assert_xml_Element(txt, tag='OrderedChoice', child_count=3) | |
98 | 104 | |
99 | 105 | |
100 | -@pytest.mark.xfail(reason="Can't test as peg.OrderedChoice() isn't implemented") | |
101 | -def test_OrderedChoice(xml_serialize): # e1 | e2 | e2 | |
102 | - e1 = peg.ID(name='ID_1') | |
103 | - e2 = peg.StrTerm(value='str_2') | |
104 | - e3 = peg.RegExpTerm(value='regexp_3') | |
105 | - txt = xml_serialize(peg.OrderedChoice()) # not implemented; never peg.OrderedChoice is never called | |
106 | +def test_OC_long(xml_serialize): # e1 | e2a e2b e2c | |
107 | + e1, seq = peg.ID(name='single_ID'), StdSequence_withAsserts() | |
108 | + txt = xml_serialize(peg.OrderedChoice(children=[e1, seq.seq])) | |
109 | + logger.debug(f'XML:: {txt}') | |
106 | 110 | |
107 | - assert False | |
111 | + assert_xml_Element(txt, tag='OrderedChoice', child_count=2) | |
112 | + |
@@ -2,10 +2,14 @@ | ||
2 | 2 | |
3 | 3 | peg_grammar <- rules ; |
4 | 4 | rules <- rule+ ; |
5 | -rule <- rule_name '<-' expressions ';' ; | |
5 | +rule <- rule_name '<-' expression ';' ; | |
6 | 6 | |
7 | -expressions <- single_expr+ ( '|' expressions )? ; | |
8 | -single_expr <- ( rule_crossref | term | group | predicate ) ( '?' | '*' | '+' | '#' )? ; | |
7 | +expression <- expressions op_alternative ; | |
8 | +expressions <- single_expr+ ; | |
9 | +single_expr <- ( rule_crossref | term | group | predicate ) op_quantity ; | |
10 | + | |
11 | +op_alternative <- ( '|' expression )? ; | |
12 | +op_quantity <- ( '?' | '*' | '+' | '#' )? ; | |
9 | 13 | |
10 | 14 | term <- str_term | regex_term ; |
11 | 15 | group <- '(' expressions ')' ; |