• R/O
  • SSH

Commit

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Castle: The best Real-Time/Embedded/HighTech language EVER. Attempt 2


Commit MetaInfo

Révisionddd4d080d1e246c71c9da2b101ada74d9369d230 (tree)
l'heure2022-01-04 07:33:12
AuteurAlbert Mietus < albert AT mietus DOT nl >
CommiterAlbert Mietus < albert AT mietus DOT nl >

Message de Log

Refactored, added some extra test

Change Summary

Modification

diff -r 9480be959415 -r ddd4d080d1e2 AST/castle/peg.py
--- a/AST/castle/peg.py Mon Jan 03 00:01:50 2022 +0100
+++ b/AST/castle/peg.py Mon Jan 03 23:33:12 2022 +0100
@@ -1,3 +1,5 @@
1+import logging; logger = logging.getLogger(__name__)
2+
13 from ._base import AST_BASE, ID, IDError
24
35 class PEG (AST_BASE): # abstract
@@ -6,26 +8,45 @@
68 super().__init__(**kwargs)
79
810
11+class MixIn_value_attribute:
12+ """With this MixIn PEG-classes get the ``.value`` property"""
13+
14+ def __init__(self, *, value=None, **kwargs):
15+ super().__init__(**kwargs)
16+ logger.debug(f'{type(self).__name__}:: value:={value}:{type(value)}')
17+ self._value=value
18+
19+ @property
20+ def value(self):
21+ logger.debug(f'{type(self).__name__}:: @property={self._value}')
22+ return self._value
23+
24+
25+class MixIn_expr_attribute:
26+ """With this MixIn PEG-classes get the ``.expr`` property"""
27+
28+ def __init__(self, *, expr=None, **kwargs):
29+ super().__init__(**kwargs)
30+ self._expr = expr
31+
32+ @property
33+ def expr(self):
34+ return self._expr
35+
936 ##
1037 ## Note: When using TypeHints with PEG-classes; the clases
1138 ## should be defined "above" the typehints uses them
1239 ## This defines (largely/partly) the order of classes.
1340 ##
1441
15-class Terminal(PEG): # abstract
16- def __init__(self, *, value=None, **kwargs):
17- super().__init__(**kwargs)
18- self.value=value
19-
20-
21-class NonTerminal(PEG): pass # abstract
22-class Markers(PEG): pass # abstract
23-
42+class Terminal(MixIn_value_attribute, PEG): pass # abstract
2443 class StrTerm(Terminal): pass
2544 class RegExpTerm(Terminal): pass
2645
27-class EOF(Markers): pass # singleton?
46+class Markers(PEG): pass # abstract
47+class EOF(Markers): pass # XXX Todo ## singleton?
2848
49+class NonTerminal(PEG): pass # abstract
2950 class Expression(NonTerminal): pass # abstract
3051
3152
@@ -42,14 +63,14 @@
4263
4364 class Rule(NonTerminal):
4465 def __init__(self, *,
45- name: ID,
46- expr :Expression=None,
66+ name: ID, expr:Expression=None,
4767 **kwargs):
4868 ID.validate_or_raise(name)
4969 super().__init__(**kwargs)
5070 self.name = name
5171 self.expr = expr
52-
72+ logger.debug(f'{type(self).__name__}:: expr:={expr}:{type(expr)}')
73+ logger.debug("\t" + "; ".join(f'{c}:{type(c)}' for c in expr))
5374
5475 class Grammar(NonTerminal):
5576 def __init__(self, *,
@@ -61,29 +82,22 @@
6182 self.settings = settings
6283
6384
64-class Group(Expression):pass # abstract -- Do not use for a '(' ...')' group, that's a Sequence!!
65-class UnorderedGroup(Group): # It looks like a Quantity, but is a group
66- def __init__(self, *, expr=None, **kwargs):
67- super().__init__(**kwargs)
68- self.expr = expr
85+class Group(Expression): pass # abstract -- Note: Do not Group for '(' ...')'; that's a Sequence!!
86+class UnorderedGroup(MixIn_expr_attribute, Group): # It looks like a Quantity, but is a group
87+ """See a set (aka "group") of expressions that **all** have to be matched, but the **order** is a don't care.
88+
89+ Possible an extension of Arpeggio (see: https://textx.github.io/Arpeggio/stable/grammars/), possible a generic one."""
90+
91+class Quantity(MixIn_expr_attribute, Expression): # abstract
92+ """An expression with Quantification; like optional, or repetition. The subclasses defines which Quantification"""
6993
7094
71-class Quantity(Expression): # abstract
72- """An expression with Quantification; like optional, or repetition. The subclasses defines which Quantification"""
73- def __init__(self, *, expr=None, **kwargs):
74- super().__init__(**kwargs)
75- self.expr = expr
76-
95+class Sequence(MixIn_value_attribute, Expression):
96+ """A _list_ of expressions; can be of length=1"""
97+ # __init__ (see MixIn) sets self._value; assuming it is a list
7798
78-class Sequence(Expression):
79- """A _list_ of expressions; can be of length=1"""
80- def __init__(self, *, value=None, **kwargs):
81- super().__init__(**kwargs)
82- self.value=value
83- def __len__(self):
84- return len(self.value)
85- def __getitem__(self, n):
86- return self.value[n]
99+ def __len__(self): return len(self._value)
100+ def __getitem__(self, n): return self._value[n]
87101
88102
89103 class OrderedChoice(Expression):pass # It a an set of alternatives
diff -r 9480be959415 -r ddd4d080d1e2 AST/pytst/test_1_Rules.py
--- a/AST/pytst/test_1_Rules.py Mon Jan 03 00:01:50 2022 +0100
+++ b/AST/pytst/test_1_Rules.py Mon Jan 03 23:33:12 2022 +0100
@@ -2,6 +2,7 @@
22
33 from castle.peg import Rule
44
5+@pytest.mark.skip("This test is wrong: (1) An ID is not string, (2) a int is not an Expression")
56 def test_a_ID():
67 a_name, a_val = 'aName', 42
78 s=Rule(name=a_name, expr=a_val)
diff -r 9480be959415 -r ddd4d080d1e2 Arpeggio/pytst/d2_ast/test_3_Seq.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Arpeggio/pytst/d2_ast/test_3_Seq.py Mon Jan 03 23:33:12 2022 +0100
@@ -0,0 +1,53 @@
1+"""Test that a sequence of expressions is an Expression()
2+
3+ Note: the value of Expression() is a list-subclass; which is fine. But use it as list!!"""
4+
5+import pytest
6+import logging; logger = logging.getLogger(__name__)
7+
8+import grammar
9+from castle import peg # has the AST classes
10+
11+from . import parse, assert_ID
12+
13+def test_seq_of_one_as_single_expr():
14+ txt = "A"
15+ ast = parse(txt, grammar.single_expr)
16+
17+ assert_ID(ast, 'A'), "An Id as single_expr results in an ID()"
18+
19+def test_seq_of_two_is_NOT_a_single_expression():
20+ txt = "A B"
21+ with pytest.raises(AssertionError):
22+ ast = parse(txt, grammar.single_expr)
23+
24+
25+def test_seq_of_two_as_expressions():
26+ txt = "A B"
27+ ast = parse(txt, grammar.expressions)
28+
29+ assert isinstance(ast, peg.Expression), "Two sequence of two expr is an Expression()"
30+ assert isinstance(ast, peg.Sequence), " ... and a Sequence()"
31+ assert len(ast) == 2, " ... of length==2"
32+
33+ assert isinstance(ast.value, list), "It will be an `arpeggio.SemanticActionResult` which is a subclass of list"
34+ assert_ID(ast[0], 'A'), " ... the first one is ID('A')"
35+ assert_ID(ast[1], 'B'), "... and the 2nd: ID('B')"
36+
37+
38+def test_seq_of_thre_with_quantification():
39+ txt = "A? B+ C*"
40+ ast = parse(txt, grammar.expressions)
41+
42+ assert isinstance(ast, peg.Expression), "Two sequence of two expr is an Expression()"
43+ assert isinstance(ast, peg.Sequence), " ... and a Sequence()"
44+ assert len(ast) == 3, " ... of length==3"
45+
46+ assert isinstance(ast[0], peg.Optional)
47+ assert isinstance(ast[1], peg.OneOrMore)
48+ assert isinstance(ast[2], peg.ZeroOrMore)
49+
50+ assert_ID(ast[0].expr, 'A'), "The first ID is an 'A'"
51+ assert_ID(ast[1].expr, 'B'), "The 2nd ID is a 'B'"
52+ assert_ID(ast[2].expr, 'C'), "The 3th one is a 'C'"
53+
diff -r 9480be959415 -r ddd4d080d1e2 Arpeggio/pytst/d2_ast/test_3_rule.py
--- a/Arpeggio/pytst/d2_ast/test_3_rule.py Mon Jan 03 00:01:50 2022 +0100
+++ b/Arpeggio/pytst/d2_ast/test_3_rule.py Mon Jan 03 23:33:12 2022 +0100
@@ -1,4 +1,5 @@
11 import pytest
2+import logging; logger = logging.getLogger(__name__)
23
34 import grammar
45 from castle import peg # has the AST classes
@@ -17,7 +18,7 @@
1718 expr = ast.expr;
1819 assert isinstance(expr, peg.Expression), "The expression is an Expression ..."
1920 assert isinstance(expr, peg.Sequence), " .. and a Sequence .."
20- assert len(expr) ==1, " .. of length==1"
21+ assert len(expr) == 1, " .. of length==1"
2122 assert_ID(expr[0], txt.split()[2], "The single element of the expression is an ID (the 2nd) -- which name is the 3 part of the txt")
2223
2324
diff -r 9480be959415 -r ddd4d080d1e2 Arpeggio/pytst/d2_ast/test_4_quantity.py
--- a/Arpeggio/pytst/d2_ast/test_4_quantity.py Mon Jan 03 00:01:50 2022 +0100
+++ b/Arpeggio/pytst/d2_ast/test_4_quantity.py Mon Jan 03 23:33:12 2022 +0100
@@ -1,7 +1,7 @@
11 """ Test several optional parts of an expression -- mosty quantity suffixes like '?' '*' and '+' -- also '#' although is different"""
22
33 import pytest
4-import logging;logger = logging.getLogger(__name__)
4+import logging; logger = logging.getLogger(__name__)
55
66 import grammar
77 from castle import peg # has the AST classes
diff -r 9480be959415 -r ddd4d080d1e2 Arpeggio/pytst/d2_ast/test_5_group.py
--- a/Arpeggio/pytst/d2_ast/test_5_group.py Mon Jan 03 00:01:50 2022 +0100
+++ b/Arpeggio/pytst/d2_ast/test_5_group.py Mon Jan 03 23:33:12 2022 +0100
@@ -1,5 +1,5 @@
11 import pytest
2-import logging;logger = logging.getLogger(__name__)
2+import logging; logger = logging.getLogger(__name__)
33
44 import grammar
55 from castle import peg # has the AST classes
diff -r 9480be959415 -r ddd4d080d1e2 Arpeggio/visitor.py
--- a/Arpeggio/visitor.py Mon Jan 03 00:01:50 2022 +0100
+++ b/Arpeggio/visitor.py Mon Jan 03 23:33:12 2022 +0100
@@ -31,19 +31,19 @@
3131 def visit_single_expr(self, node, children): # [ rule_crossref, term, group, predicate ], expr_quantity
3232 if len(children) == 1: # No Optional part
3333 try:
34- n = children[0].name
34+ n = f'name={children[0].name}'
3535 except AttributeError:
36- n = str(children[0])
36+ n = f'name:{children[0]}'
3737 logger.debug(f'visit_single_expr==1:: {n}:{type(children[0])}')
3838 return children[0]
3939 elif len(children) == 2: # Optional part
40- logger.debug(f'visit_single_expr==2:: {children[0]}, {children[1]}')
40+ logger.debug(f'visit_single_expr==2::Got: {children[0]}, {children[1]}')
4141 expr = children[0]
4242 token = str(children[1])
4343 quantum_cls = self.token_2_class.get(token)
4444 if quantum_cls:
4545 ast=quantum_cls(expr=expr, parse_tree=node)
46- logger.debug(f'visit_single_expr==2:: {quantum_cls} {expr}')
46+ logger.debug(f'visit_single_expr==2::Pass: {quantum_cls}(expr={expr})')
4747 return ast
4848 else:
4949 raise QuantityError(f"token '{token}' not recognised")
@@ -56,6 +56,6 @@
5656
5757
5858 def visit_expressions(self, node, children): # OneOrMore(single_expr), Optional( '|' , expressions )
59- logger.debug(f'>>{node}<< len={len(children)} children={children}')
59+ logger.debug(f'visit_expressions:: >>{node}<< len={len(children)} children={children}:{type(children)}')
6060 return peg.Sequence(value=children, parse_tree=node)
6161