• 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évisionf0bc39d34f56083b4ca3345023730d8ded559f50 (tree)
l'heure2022-01-03 05:43:48
AuteurAlbert Mietus < albert AT mietus DOT nl >
CommiterAlbert Mietus < albert AT mietus DOT nl >

Message de Log

Added Quantification (former: 'many') suffix as '*','+','?'. --Needed to move the optional part to a sub-rule, to be able to visit it

Change Summary

Modification

diff -r 7dbab792d37e -r f0bc39d34f56 AST/castle/peg.py
--- a/AST/castle/peg.py Sat Jan 01 20:38:16 2022 +0100
+++ b/AST/castle/peg.py Sun Jan 02 21:43:48 2022 +0100
@@ -61,12 +61,19 @@
6161 self.settings = settings
6262
6363
64+class Group(Expression):pass # abstract
65+class UnorderedGroup(Group):pass # It looks like a Quantity, but is a group
6466
65-class ManyExpression(Expression): pass # abstract
66-class Group(Expression):pass
67+
68+class Quantity(Expression): # abstract
69+ """An expression with Quantification; like optional, or repetition. The subclasses defines which Quantification"""
70+ def __init__(self, *, expr=None, **kwargs):
71+ super().__init__(**kwargs)
72+ self.expr = expr
73+
6774
6875 class Sequence(Expression):
69- """A "list of expressions; can be of length=1"""
76+ """A _list_ of expressions; can be of length=1"""
7077 def __init__(self, *, value=None, **kwargs):
7178 super().__init__(**kwargs)
7279 self.value=value
@@ -76,12 +83,14 @@
7683 return self.value[n]
7784
7885
79-class OrderedChoice(Expression):pass
80-class Predicate(Expression): pass # abstract
86+class OrderedChoice(Expression):pass # It a an set of alternatives
8187
82-class Optional(ManyExpression):pass
83-class OneOrMore(ManyExpression):pass
84-class ZeroOrMore(ManyExpression):pass
8588
89+class Optional(Quantity):pass
90+class ZeroOrMore(Quantity):pass
91+class OneOrMore(Quantity):pass
92+
93+
94+class Predicate(Expression): pass # abstract
8695 class AndPredicate(Predicate): pass
8796 class NotPredicate(Predicate): pass
diff -r 7dbab792d37e -r f0bc39d34f56 AST/pytst/test_0.py
--- a/AST/pytst/test_0.py Sat Jan 01 20:38:16 2022 +0100
+++ b/AST/pytst/test_0.py Sun Jan 02 21:43:48 2022 +0100
@@ -10,7 +10,7 @@
1010
1111 def test_abstracts_2():
1212 assert isinstance(peg.Expression(), peg.NonTerminal)
13- assert isinstance(peg.ManyExpression(), peg.Expression)
13+ assert isinstance(peg.Quantity(), peg.Expression)
1414 assert isinstance(peg.Predicate(), peg.Expression)
1515
1616 def test_eof():
@@ -21,6 +21,6 @@
2121 assert isinstance(peg.NotPredicate(), peg.Predicate)
2222
2323 def test_manys():
24- assert isinstance(peg.Optional(), peg.ManyExpression)
25- assert isinstance(peg.OneOrMore(), peg.ManyExpression)
26- assert isinstance(peg.ZeroOrMore(), peg.ManyExpression)
24+ assert isinstance(peg.Optional(), peg.Quantity)
25+ assert isinstance(peg.OneOrMore(), peg.Quantity)
26+ assert isinstance(peg.ZeroOrMore(), peg.Quantity)
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/demo/test_Rule.py
--- a/Arpeggio/demo/test_Rule.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/demo/test_Rule.py Sun Jan 02 21:43:48 2022 +0100
@@ -1,4 +1,5 @@
11 import pytest
2+import logging;logger = logging.getLogger(__name__)
23
34 import grammar
45 import arpeggio
@@ -13,7 +14,7 @@
1314
1415 def show_visited(label="VISIT_", node=None, children=None):
1516 nl= "\n" if label[-1] != '_' else ""
16- print(f'XXX {label}{nl}{format_node(node)}{format_children(children)}')
17+ logger.info(f'{label}{nl}{format_node(node)}{format_children(children)}')
1718
1819
1920
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/grammar.py
--- a/Arpeggio/grammar.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/grammar.py Sun Jan 02 21:43:48 2022 +0100
@@ -7,8 +7,9 @@
77 def rule(): return rule_name, '<-', expressions, ";"
88
99 def expressions(): return ( OneOrMore(single_expr), Optional( '|' , expressions ) )
10-def single_expr(): return ( [ rule_crossref, term, group, predicate ], Optional([ '?' , '*' , '+' , '#' ]))
10+def single_expr(): return ( [ rule_crossref, term, group, predicate ], expr_quantity)
1111
12+def expr_quantity(): return Optional([ '?' , '*' , '+' , '#' ])
1213 def term(): return [ str_term, regex_term ]
1314 def group(): return '(', expressions, ')'
1415 def predicate(): return ['&','!'], single_expr
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d1_parse_tree/test_1_regexp.py
--- a/Arpeggio/pytst/d1_parse_tree/test_1_regexp.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/pytst/d1_parse_tree/test_1_regexp.py Sun Jan 02 21:43:48 2022 +0100
@@ -1,11 +1,13 @@
11 import pytest
2+import logging;logger = logging.getLogger(__name__)
3+
24 from grammar import *
35
46 import arpeggio
57 RE, S = arpeggio.RegExMatch, arpeggio.StrMatch # shortcut
68
79 def parse_regex(txt, pattern=None):
8- #print(f'\nXXX >>{txt}<<')
10+ logger.debug(f'>>{txt}<<')
911 parser = ParserPython(regex_term, comment) # DoNot use debug/dot_exporter as it will re-use-same-file
1012 tree = parser.parse(txt)
1113 assert tree.position_end == len(txt) , f"Not parsed whole input; Only: >>{txt[tree.position: tree.position_end]}<<; Not: >>{txt[tree.position_end:]}<<."
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d1_parse_tree/test_2_str.py
--- a/Arpeggio/pytst/d1_parse_tree/test_2_str.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/pytst/d1_parse_tree/test_2_str.py Sun Jan 02 21:43:48 2022 +0100
@@ -1,4 +1,5 @@
11 import pytest
2+import logging;logger = logging.getLogger(__name__)
23
34 from grammar import *
45 import arpeggio
@@ -6,7 +7,7 @@
67
78
89 def parse_str(str, pattern=[S, RE, S]):
9- #print(f'\nXXX >>{str}<<')
10+ logger.debug(f'>>{str}<<')
1011 parser = ParserPython(str_term, comment)
1112 tree = parser.parse(str)
1213 assert tree.position_end == len(str) , f"Not parsed whole input; Only: >>{str[tree.position: tree.position_end]}<<; Not: >>{str[tree.position_end:]}<<."
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d1_parse_tree/test_3_expressions.py
--- a/Arpeggio/pytst/d1_parse_tree/test_3_expressions.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/pytst/d1_parse_tree/test_3_expressions.py Sun Jan 02 21:43:48 2022 +0100
@@ -1,6 +1,7 @@
11 import pytest
2+import logging;logger = logging.getLogger(__name__)
3+
24 import grammar
3-
45 import arpeggio
56
67 R, S, X = grammar.regex_term.__name__, grammar.str_term.__name__, grammar.rule_crossref.__name__ # shortcut in grammar
@@ -10,7 +11,7 @@
1011 def parse_expressions(txt, pattern=None):
1112 parser = arpeggio.ParserPython(grammar.expressions)
1213 parse_tree = parser.parse(txt)
13- print("\nPARSE-TREE\n" + parse_tree.tree_str()+'\n')
14+ logger.info("\nPARSE-TREE\n" + parse_tree.tree_str()+'\n')
1415
1516 assert parse_tree.position_end == len(txt) , f"Not parsed whole input; Only: >>{txt[parse_tree.position: parse_tree.position_end]}<<; Not: >>{txt[parse_tree.position_end:]}<<."
1617 assert parse_tree.rule_name == "expressions"
@@ -20,7 +21,6 @@
2021 return parse_tree
2122
2223 def validate_pattern(pt, pattern=None):
23- print('VVV', pt, type(pt))
2424 assert len(pt) == len(pattern), f"Not correct number-of-element"
2525
2626 for p, s in zip(pattern, pt): # E <- S* (| E)?
@@ -31,14 +31,11 @@
3131 assert s[0][0].rule_name == p # S => T => str/regex
3232 elif isinstance(p, tuple): # Group: '(' ... ')'
3333 assert s[0].rule_name == G
34- print("\nVVV:G\n" + s.tree_str())
35- # XXXXX
3634 validate_pattern(s[0][1:-1][0], pattern=p) # G=>E=>
3735 elif p == P:
3836 assert False, "To Do: Predicate"
3937 else:
4038 assert False, "To Do: More"
41- print('VVV OKE')
4239
4340
4441 def test_simple_1(): parse_expressions(r"abc", pattern=[X])
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d1_parse_tree/test_4_rule.py
--- a/Arpeggio/pytst/d1_parse_tree/test_4_rule.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/pytst/d1_parse_tree/test_4_rule.py Sun Jan 02 21:43:48 2022 +0100
@@ -1,4 +1,6 @@
11 import pytest
2+import logging;logger = logging.getLogger(__name__)
3+
24 import grammar
35
46 import arpeggio
@@ -7,7 +9,7 @@
79 def parse_rule(txt, pattern=None):
810 parser = arpeggio.ParserPython(grammar.rule)
911 tree = parser.parse(txt)
10- print(f'\nTREE\n{tree.tree_str()}')
12+ logger.info(f'\nTREE\n{tree.tree_str()}')
1113
1214 assert tree.position_end == len(txt) , f"Not parsed whole input; Only: >>{txt[tree.position: tree.position_end]}<<; Not: >>{txt[tree.position_end:]}<<."
1315 assert len(tree) == 4, "A rule should have length=4; ..."
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d2_ast/__init__.py
--- a/Arpeggio/pytst/d2_ast/__init__.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/pytst/d2_ast/__init__.py Sun Jan 02 21:43:48 2022 +0100
@@ -4,11 +4,15 @@
44 import sys; sys.path.append("./../AST/") ; sys.path.append("./../../AST/")
55 from castle import peg # has the AST clases
66
7-def parse(txt, rule):
7+def parse(txt, rule,
8+ print_tree_debug=False,
9+ visitor_debug=False):
810 parser = arpeggio.ParserPython(rule)
911 pt = parser.parse(txt)
12+ if print_tree_debug:
13+ print('\n'+pt.tree_str())
1014 assert pt.position_end == len(txt), f"Did not parse all input txt=>>{txt}<<len={len(txt)} ==> parse_tree: >>{pt}<<_end={pt.position_end}"
11- ast = arpeggio.visit_parse_tree(pt, visitor.PegVisitor())
15+ ast = arpeggio.visit_parse_tree(pt, visitor.PegVisitor(debug=visitor_debug))
1216 assert ast.position == 0 and ast.position_end == len(txt), f"Also the AST (type={type(ast)}) should include all input"
1317 return ast
1418
@@ -18,3 +22,5 @@
1822 assert isinstance(id, peg.ID), "The id should be an ID"
1923 peg.ID.validate_or_raise(id) # with correct syntax
2024 assert id.name == name, err_message if err_message else f"Note correct name, expected {name}"
25+
26+
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d2_ast/test_1_term.py
--- a/Arpeggio/pytst/d2_ast/test_1_term.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/pytst/d2_ast/test_1_term.py Sun Jan 02 21:43:48 2022 +0100
@@ -1,7 +1,7 @@
11 import pytest
22
33 import grammar
4-from castle import peg # has the AST clases
4+from castle import peg # has the AST classes
55
66 from . import parse
77
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d2_ast/test_2_ID.py
--- a/Arpeggio/pytst/d2_ast/test_2_ID.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/pytst/d2_ast/test_2_ID.py Sun Jan 02 21:43:48 2022 +0100
@@ -1,7 +1,7 @@
11 import pytest
22
33 import grammar
4-from castle import peg # has the AST clases
4+from castle import peg # has the AST classes
55
66 from . import parse, assert_ID
77
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d2_ast/test_3_rule.py
--- a/Arpeggio/pytst/d2_ast/test_3_rule.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/pytst/d2_ast/test_3_rule.py Sun Jan 02 21:43:48 2022 +0100
@@ -1,7 +1,7 @@
11 import pytest
22
33 import grammar
4-from castle import peg # has the AST clases
4+from castle import peg # has the AST classes
55
66 from . import parse, assert_ID
77
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/pytst/d2_ast/test_4_quantity.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Arpeggio/pytst/d2_ast/test_4_quantity.py Sun Jan 02 21:43:48 2022 +0100
@@ -0,0 +1,35 @@
1+""" Test several optional parts of an expression -- mosty quantity suffixes like '?' '*' and '+' -- also '#' although is different"""
2+
3+import pytest
4+import logging;logger = logging.getLogger(__name__)
5+
6+import grammar
7+from castle import peg # has the AST classes
8+
9+from . import parse, assert_ID
10+
11+def assert_Quantification(token:str, kind:type(peg.Quantity)):
12+ txt = f"R <- X {token} ;"
13+
14+ ast = parse(txt, grammar.rule)
15+ assert_ID(ast.name, 'R')
16+
17+ expr = ast.expr
18+ assert len(expr)==1, "There should be only one expr"
19+
20+ assert isinstance(expr[0], peg.Quantity), "It should be a (sub of) Quantity .."
21+ assert isinstance(expr[0], kind), f"... namely the specified one: {kind}"
22+
23+ opt_ex = expr[0].expr
24+ assert_ID(opt_ex, 'X', "should be same a the expr; without the Quantification")
25+
26+
27+def test_Optional():
28+ assert_Quantification('?', peg.Optional)
29+
30+def test_ZeroOrMore():
31+ assert_Quantification('*', peg.ZeroOrMore)
32+
33+def test_OneOrMore():
34+ assert_Quantification('+', peg.OneOrMore)
35+
diff -r 7dbab792d37e -r f0bc39d34f56 Arpeggio/visitor.py
--- a/Arpeggio/visitor.py Sat Jan 01 20:38:16 2022 +0100
+++ b/Arpeggio/visitor.py Sun Jan 02 21:43:48 2022 +0100
@@ -3,7 +3,15 @@
33 import sys; sys.path.append("./../AST/") ; sys.path.append("./../../AST/")
44 from castle import peg # has the AST clases
55
6+import logging;logger = logging.getLogger(__name__)
7+
8+class QuantityError(ValueError): pass
9+
610 class PegVisitor(arpeggio.PTNodeVisitor):
11+ token_2_class = {'?': peg.Optional,
12+ '*': peg.ZeroOrMore,
13+ '+': peg.OneOrMore,
14+ '#': peg.UnorderedGroup}
715
816 def visit_str_term(self, node, children):
917 return peg.StrTerm(value=node[1], parse_tree=node)
@@ -20,15 +28,34 @@
2028 def visit_rule(self, node, children): # Name '<-' expressions ';'
2129 return peg.Rule(name=children[0],expr=children[1], parse_tree=node)
2230
31+ def visit_single_expr(self, node, children): # [ rule_crossref, term, group, predicate ], expr_quantity
32+ if len(children) == 1: # No Optional part
33+ try:
34+ n = children[0].name
35+ except AttributeError:
36+ n = str(children[0])
37+ logger.warning(f'visit_single_expr==1:: {n}:{type(children[0])}')
38+ return children[0]
39+ elif len(children) == 2: # Optional part
40+ logger.debug(f'visit_single_expr==2:: {children[0]}, {children[1]}')
41+ expr = children[0]
42+ token = str(children[1])
43+ quantum_cls = self.token_2_class.get(token)
44+ if quantum_cls:
45+ ast=quantum_cls(expr=expr, parse_tree=node)
46+ logger.debug(f'visit_single_expr==2:: {quantum_cls} {expr}')
47+ return ast
48+ else:
49+ raise QuantityError(f"token '{token}' not recognised")
50+ else:
51+ raise NotImplementedError("visit_single_expr, len>2") # XXX -- Is this possible?
2352
24-# def visit_single_expr(self, node, children): # [ rule_crossref, term, group, predicate ] Optional([ '?' , '*' , '+' , '#' ]))
25-# if len(children) == 1: # No optional part
26-# #ast = peg.Sequence(value=children, parse_tree=node)
27-# return super().visit__default__(node, children)
28-# else:
29-# assert NotImplementedError("To Do: visit_single_expr with optional part") # XXX
30-# return ast
53+ def visit_expr_quantity(self, node, children): # Optional([ '?' , '*' , '+' , '#' ])
54+ logger.debug(f'visit_expr_quantity [{len(children)}] node={node}:{type(node)}')
55+ return node
3156
32- def visit_expressions(self, node, children): # OneOrMore(single_expr), Optional( '|' , expressions )
57+
58+ def visit_expressions(self, node, children): # OneOrMore(single_expr), Optional( '|' , expressions )
59+ logger.debug(f'>>{node}<< len={len(children)} children={children}')
3360 return peg.Sequence(value=children, parse_tree=node)
3461