Castle: The best Real-Time/Embedded/HighTech language EVER. Attempt 2
Revisión | f8bd16e1d4e3920655376abe924c89460dbac0a1 (tree) |
---|---|
Tiempo | 2022-02-15 02:27:24 |
Autor | Albert Mietus < albert AT mietus DOT nl > |
Commiter | Albert Mietus < albert AT mietus DOT nl > |
SETTINGS: ASIS, promoting 'Settings' up-to grammar; but introduced BUG in visit_rules ... Need to fix some test
@@ -108,7 +108,7 @@ | ||
108 | 108 | rules: Rules=None, |
109 | 109 | settings: Settings=None, |
110 | 110 | **kwargs): |
111 | - logger.debug(f'{self._typeName(self)}:: kwargs={kwargs}') | |
111 | + logger.debug(f'{self._typeName(self)}:: rules={rules}; settings={settings}, kwargs={kwargs}') | |
112 | 112 | super().__init__(**kwargs) |
113 | 113 | self.rules = rules |
114 | 114 | self.settings = settings |
@@ -24,7 +24,7 @@ | ||
24 | 24 | #NO_VISITOR_NEEDED: visit_float_lit -- handled in visit_number |
25 | 25 | #NO_VISITOR_NEEDED: visit_int_lit -- handled in visit_number |
26 | 26 | #NO_VISITOR_NEEDED: visit_value |
27 | -#NO_VISITOR_NEEDED: visit_setting_xref | |
27 | + | |
28 | 28 | |
29 | 29 | |
30 | 30 | class PegVisitor(arpeggio.PTNodeVisitor): |
@@ -113,14 +113,16 @@ | ||
113 | 113 | |
114 | 114 | def visit_rules(self, node, children): |
115 | 115 | logger.debug('visit_rules::' + self._logstr_node_children(node, children)) |
116 | - return peg.Rules(children=children[:], parse_tree=node) | |
116 | + parse_rules = peg.Rules(children=[r for r in children if isinstance(r, peg.Rule)] ) | |
117 | + settings = peg.Settings(children=[r for r in children if isinstance(r, peg.Setting)] ) | |
118 | + assert len(children) == len(parse_rules) + len(settings), f'Number of parse_rules ({len(parse_rules)}) and settings ({len(settings)}), does not match total: {len(children)}' | |
119 | + return (parse_rules, settings) # XXX not an AST! XXX | |
117 | 120 | |
118 | 121 | |
119 | 122 | def visit_peg_grammar(self, node, children): # No support for settings XXX |
120 | - rules=children[0] | |
121 | - assert len(children) == 1 | |
122 | - logger.debug(f'visit_peg_grammar:: >>{node}<< #children={len(children)} ; rules={rules}:{type(rules)}') | |
123 | - return peg.Grammar(rules=rules, parse_tree=node) | |
123 | + logger.debug('visit_peg_grammar::' + self._logstr_node_children(node, children)) | |
124 | + parse_rules, settings = children[0] #unpack the tuple of above | |
125 | + return peg.Grammar(rules=parse_rules, settings=settings, parse_tree=node) | |
124 | 126 | |
125 | 127 | |
126 | 128 | def visit_setting_name(self, node, children): |
@@ -129,6 +131,9 @@ | ||
129 | 131 | def visit_number(self, node, children): |
130 | 132 | return peg.Number(value=str(node), parse_tree=node) |
131 | 133 | |
134 | + def visit_setting_xref(self, node, children): | |
135 | + return peg.ID(name=str(node), parse_tree=node) | |
136 | + | |
132 | 137 | def visit_setting(self, node, children): |
133 | 138 | logger.debug('visit_setting::' + self._logstr_node_children(node, children)) |
134 | 139 | return peg.Setting(name=children[0], value=children[1] , parse_tree=node) |
@@ -43,12 +43,14 @@ | ||
43 | 43 | assert_ID(ast[i], name) |
44 | 44 | |
45 | 45 | |
46 | -def assert_Rule(ast, rune_name=None): | |
46 | +def assert_ParseRule(ast, rule_name=None): | |
47 | 47 | assert isinstance(ast, peg.Rule), "It should be an Rule" |
48 | - if rune_name: | |
49 | - assert_ID(ast.name, rune_name) | |
50 | -precondition_Rule = assert_Rule | |
48 | + if rule_name: assert_ID(ast.name, rule_name) | |
51 | 49 | |
50 | +def assert_Rule(ast, rule_name=None): | |
51 | + assert isinstance(ast, (peg.Rule, peg.Setting)) | |
52 | + if isinstance(ast, peg.Rule): assert_ParseRule(ast, rule_name) | |
53 | + if isinstance(ast, peg.Setting): assert_Setting(ast, rule_name) | |
52 | 54 | |
53 | 55 | def precondition_Expressions(expr, *, type=peg.Sequence, length=None): |
54 | 56 | assert isinstance(expr, type), "PreCondition failed" |
@@ -62,10 +64,20 @@ | ||
62 | 64 | rules = ast.rules |
63 | 65 | assert isinstance(rules, peg.Rules) |
64 | 66 | if no_of_rules: |
65 | - assert len(rules) == no_of_rules, "We expect the same number as Rules as lines" | |
67 | + assert len(rules) == no_of_rules, f"The number of (parse_)rules ({len(rules)}) does not match the spec: {no_of_rules}" | |
66 | 68 | |
67 | 69 | settings = ast.settings |
68 | - assert isinstance(settings, (type(None), peg.Settings)) | |
70 | + if settings: | |
71 | + assert isinstance(settings, peg.Settings) | |
69 | 72 | if no_of_settings: |
70 | - assert isinstance(settings, peg.Settings) | |
71 | - len(settings) == no_of_settings | |
73 | + assert len(settings) == no_of_settings, f"The number of settings ({len(settings)}) does not match the spec: {no_of_settings}" | |
74 | + | |
75 | + | |
76 | +def assert_Setting(ast, pegType=None, name=None, value=None): | |
77 | + assert isinstance(ast, peg.Setting) | |
78 | + assert isinstance(ast.name, peg.ID) | |
79 | + assert isinstance(ast.value, (peg.StrTerm, peg.RegExpTerm, peg.Number, peg.ID)), f'Unexpected Type for ast.value: {type(ast.value)}' | |
80 | + | |
81 | + if pegType: assert isinstance(ast.value, pegType) | |
82 | + if name: assert ast.name.name == name | |
83 | + if value: assert ast.value.value == value |
@@ -4,7 +4,7 @@ | ||
4 | 4 | from castle.readers.parser import grammar |
5 | 5 | from castle.ast import peg |
6 | 6 | |
7 | -from . import parse, assert_ID, assert_Seq, assert_Rule | |
7 | +from . import parse, assert_ID, assert_Seq, assert_ParseRule | |
8 | 8 | |
9 | 9 | |
10 | 10 | def test_trivial_rule_with_2IDS(): |
@@ -13,7 +13,7 @@ | ||
13 | 13 | txt="trivial <- cross ;" |
14 | 14 | ast = parse(txt, grammar.parse_rule) |
15 | 15 | |
16 | - assert_Rule(ast, rune_name=txt.split()[0]) # The name of a rule is a ID with the left-side ID as name | |
16 | + assert_ParseRule(ast, rule_name=txt.split()[0]) # The name of a rule is a ID with the left-side ID as name | |
17 | 17 | |
18 | 18 | expr = ast.expr |
19 | 19 | assert_Seq(expr, length=1) |
@@ -24,7 +24,7 @@ | ||
24 | 24 | txt = """aRule <- 'aStr' aCross /regexp/ ;""" |
25 | 25 | ast = parse(txt, grammar.parse_rule) |
26 | 26 | |
27 | - assert_Rule(ast, rune_name=txt.split()[0]) | |
27 | + assert_ParseRule(ast, rule_name=txt.split()[0]) | |
28 | 28 | |
29 | 29 | expr = ast.expr; |
30 | 30 | assert_Seq(expr, length=3) |
@@ -3,34 +3,32 @@ | ||
3 | 3 | from castle.readers.parser import grammar |
4 | 4 | from castle.ast import peg |
5 | 5 | |
6 | -from . import parse | |
7 | - | |
8 | -def validate_setting(ast, pegType=None, name=None, value=None): | |
9 | - assert isinstance(ast, peg.Setting) | |
10 | - assert isinstance(ast.name, peg.ID) | |
11 | - assert isinstance(ast.value, (peg.StrTerm, peg.RegExpTerm, peg.Number)) | |
12 | - | |
13 | - if pegType: assert isinstance(ast.value, pegType) | |
14 | - if name: assert ast.name.name == name | |
15 | - if value: assert ast.value.value == value | |
6 | +from . import parse, assert_Setting | |
16 | 7 | |
17 | 8 | |
18 | 9 | def test_setting_a_value42(): |
19 | 10 | txt="aNumber = 42;" |
20 | 11 | ast = parse(txt, grammar.setting) |
21 | - validate_setting(ast, pegType=peg.Number, name='aNumber', value='42') | |
12 | + assert_Setting(ast, pegType=peg.Number, name='aNumber', value='42') | |
22 | 13 | |
23 | 14 | def test_setting_str1(): |
24 | 15 | txt="String = '42';" |
25 | 16 | ast = parse(txt, grammar.setting) |
26 | - validate_setting(ast, pegType=peg.StrTerm, name='String', value='42') | |
17 | + assert_Setting(ast, pegType=peg.StrTerm, name='String', value='42') | |
27 | 18 | |
28 | 19 | def test_setting_str2(): |
29 | 20 | txt='''String = "42";''' |
30 | 21 | ast = parse(txt, grammar.setting) |
31 | - validate_setting(ast, pegType=peg.StrTerm, name='String', value='42') | |
22 | + assert_Setting(ast, pegType=peg.StrTerm, name='String', value='42') | |
32 | 23 | |
33 | 24 | def test_setting_re(): |
34 | 25 | txt="RegExp = /abc/;" |
35 | 26 | ast = parse(txt, grammar.setting) |
36 | - validate_setting(ast, pegType=peg.RegExpTerm, name='RegExp', value='abc') | |
27 | + assert_Setting(ast, pegType=peg.RegExpTerm, name='RegExp', value='abc') | |
28 | + | |
29 | +def test_setting_setting_xref(): | |
30 | + txt="aSetting = anOtherSetting;" | |
31 | + ast = parse(txt, grammar.setting) | |
32 | + assert_Setting(ast, pegType=peg.ID, name='aSetting') | |
33 | + assert ast.value.name == 'anOtherSetting' | |
34 | + |
@@ -4,7 +4,7 @@ | ||
4 | 4 | from castle.readers.parser import grammar |
5 | 5 | from castle.ast import peg |
6 | 6 | |
7 | -from . import parse, assert_ID, precondition_Rule, assert_Seq | |
7 | +from . import parse, assert_ID, assert_ParseRule, assert_Seq | |
8 | 8 | |
9 | 9 | |
10 | 10 | def assert_Group(grp, length=1, groupType=peg.Sequence, ids=None): |
@@ -18,7 +18,7 @@ | ||
18 | 18 | txt = "R <- ( A B ) ;" |
19 | 19 | |
20 | 20 | ast = parse(txt, grammar.parse_rule) |
21 | - precondition_Rule(ast, 'R') | |
21 | + assert_ParseRule(ast, 'R') | |
22 | 22 | |
23 | 23 | grp = ast.expr |
24 | 24 | assert_Group(grp, ids=('A', 'B')) |
@@ -28,7 +28,7 @@ | ||
28 | 28 | txt = "R <- ( ( A B ) ) ;" |
29 | 29 | |
30 | 30 | ast = parse(txt, grammar.parse_rule) |
31 | - precondition_Rule(ast, 'R') | |
31 | + assert_ParseRule(ast, 'R') | |
32 | 32 | |
33 | 33 | grp = ast.expr |
34 | 34 | assert_Group(grp) |
@@ -41,7 +41,7 @@ | ||
41 | 41 | txt = "R <- ( A B )# ;" |
42 | 42 | |
43 | 43 | ast = parse(txt, grammar.parse_rule) |
44 | - precondition_Rule(ast, 'R') | |
44 | + assert_ParseRule(ast, 'R') | |
45 | 45 | |
46 | 46 | grp = ast.expr |
47 | 47 | assert_Group(grp, groupType=peg.UnorderedGroup) |
@@ -4,11 +4,31 @@ | ||
4 | 4 | from castle.readers.parser import grammar |
5 | 5 | from castle.ast import peg |
6 | 6 | |
7 | -from . import parse, assert_Rule | |
7 | +from . import parse, assert_Rule, assert_ParseRule, assert_Setting | |
8 | 8 | |
9 | -def test_some_rules(): | |
9 | +def test_some_parse_rules(): | |
10 | 10 | txt="""R1 <- A; |
11 | 11 | R2 <- B;""" |
12 | + ast = parse(txt, grammar.rules) | |
13 | + | |
14 | + assert isinstance(ast, peg.Rules) | |
15 | + assert len(ast) == 2, "We expect the same number as Rules as lines" | |
16 | + for p in ast: | |
17 | + assert_ParseRule(p) | |
18 | + | |
19 | +def test_some_setting_rules(): | |
20 | + txt="""S1 = A; | |
21 | + S2 = 42;""" | |
22 | + ast = parse(txt, grammar.rules, visitor_debug=False) | |
23 | + | |
24 | + assert isinstance(ast, peg.Rules) | |
25 | + assert len(ast) == 2, "We expect the same number as Rules as lines" | |
26 | + for s in ast: | |
27 | + assert_Setting(s) | |
28 | + | |
29 | +def test_mixed_rules(): | |
30 | + txt="""M1 <- A; | |
31 | + M2 = B;""" | |
12 | 32 | ast = parse(txt, grammar.rules, visitor_debug=False) |
13 | 33 | |
14 | 34 | assert isinstance(ast, peg.Rules) |
@@ -17,3 +37,4 @@ | ||
17 | 37 | assert_Rule(r) |
18 | 38 | |
19 | 39 | |
40 | + |
@@ -26,6 +26,7 @@ | ||
26 | 26 | ast = parse(txt, grammar.peg_grammar, with_comments=True) |
27 | 27 | assert_PEG(ast, no_of_rules=2) |
28 | 28 | |
29 | + | |
29 | 30 | def test_with_start_comment(): |
30 | 31 | txt="""// COMMENT |
31 | 32 | R1 <- A; |
@@ -33,4 +34,24 @@ | ||
33 | 34 | ast = parse(txt, grammar.peg_grammar, with_comments=True) |
34 | 35 | assert_PEG(ast, no_of_rules=2) |
35 | 36 | |
37 | +def test_grammar_with_mixed_rules(): | |
38 | + txt="""M1 <- A; | |
39 | + M2 = B;""" | |
40 | + ast = parse(txt, grammar.peg_grammar) | |
36 | 41 | |
42 | + assert isinstance(ast, peg.Grammar) | |
43 | + assert_PEG(ast, no_of_rules=1, no_of_settings=1) | |
44 | + | |
45 | +def test_grammar_with_many_rules(): | |
46 | + txt="""R1 <- a; | |
47 | + R2 <- bb; | |
48 | + S1 = 1; | |
49 | + R3 <- ccc; | |
50 | + R4 <- dddd; | |
51 | + S2 = 2; | |
52 | + R5 <- eeeee; | |
53 | + S3 = 3;""" | |
54 | + ast = parse(txt, grammar.peg_grammar) | |
55 | + | |
56 | + assert isinstance(ast, peg.Grammar) | |
57 | + assert_PEG(ast, no_of_rules=5, no_of_settings=3) |