Преглед изворни кода

Moved argument parser and added 'hint' and 'apply'

Introduced new symbols "?" (suggest hint) and '@' (apply one suggestion).
Moved the argument parser to main.py.

Removed replace from expression{leaf,node}.
Sander Mathijs van Veen пре 14 година
родитељ
комит
04ffd70216
4 измењених фајлова са 88 додато и 67 уклоњено
  1. 52 2
      main.py
  2. 0 15
      src/node.py
  3. 26 50
      src/parser.py
  4. 10 0
      src/possibilities.py

+ 52 - 2
main.py

@@ -1,8 +1,17 @@
 #!/usr/bin/python
 #!/usr/bin/python
+"""
+Shell front-end for the mathematical term rewriting system. This shell will
+parse mathematical expressions into an expression tree, produce possible
+rewrite steps and, if requested, provide a hint to rewrite the last entered
+expression.
+"""
+
+import argparse
+import sys
+import os
 
 
 
 
 def init_readline():
 def init_readline():
-    import os
     try:
     try:
         import readline
         import readline
     except ImportError:
     except ImportError:
@@ -19,7 +28,48 @@ def init_readline():
     atexit.register(readline.write_history_file, histfile)
     atexit.register(readline.write_history_file, histfile)
 
 
 
 
+def get_args():
+    parser = argparse.ArgumentParser(prog='trs', description=__doc__)
+
+    parser.add_argument('--debug', '-d', action='store_true',
+            default=False,
+            help='Enable debug mode in bison and flex.')
+    parser.add_argument('--verbose', '-v', action='store_true',
+            default=False,
+            help='Enable verbose output messages (printed to stdout).')
+    parser.add_argument('--keepfiles', '-k', action='store_true',
+            default=False,
+            help='Keep temporary generated bison and lex files.')
+    parser.add_argument('--batch', '-b', action='store_true', default=False,
+            help='Disable interactive mode and execute expressions in batch' \
+                 ' mode.')
+    parser.add_argument('--interactive', action='store_true',
+            default=sys.stdin.isatty(),
+            help='Enable interactive mode (default). This is the inverse of' \
+                 ' --batch.')
+
+    return parser.parse_args()
+
+
+def main():
+    from src.parser import Parser
+
+    args = get_args()
+    interactive = args.interactive and not args.batch
+
+    p = Parser(verbose=args.verbose,
+               keepfiles=args.keepfiles,
+               interactive=interactive)
+
+    node = p.run(debug=args.debug)
+
+    # Clear the line, when the shell exits.
+    if interactive:
+        print
+
+    return node
+
+
 if __name__ == '__main__':
 if __name__ == '__main__':
-    from src.parser import main
     init_readline()
     init_readline()
     main()
     main()

+ 0 - 15
src/node.py

@@ -128,12 +128,6 @@ class ExpressionNode(Node, ExpressionBase):
     def graph(self):  # pragma: nocover
     def graph(self):  # pragma: nocover
         return generate_graph(self)
         return generate_graph(self)
 
 
-    def replace(self, node):
-        pos = self.parent.nodes.index(self)
-        self.parent.nodes[pos] = node
-        node.parent = self.parent
-        self.parent = None
-
     def extract_polynome_properties(self):
     def extract_polynome_properties(self):
         """
         """
         Extract polynome properties into tuple format: (coefficient, root,
         Extract polynome properties into tuple format: (coefficient, root,
@@ -219,12 +213,3 @@ class ExpressionLeaf(Leaf, ExpressionBase):
         """
         """
         # rule: 1 * r ^ 1 -> (1, r, 1)
         # rule: 1 * r ^ 1 -> (1, r, 1)
         return (ExpressionLeaf(1), self, ExpressionLeaf(1))
         return (ExpressionLeaf(1), self, ExpressionLeaf(1))
-
-    def replace(self, node):
-        if not hasattr(self, 'parent'):
-            return
-
-        pos = self.parent.nodes.index(self)
-        self.parent.nodes[pos] = node
-        node.parent = self.parent
-        self.parent = None

+ 26 - 50
src/parser.py

@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 """
 """
 This parser will parse the given input and build an expression tree. Grammar
 This parser will parse the given input and build an expression tree. Grammar
 file for the supported mathematical expressions.
 file for the supported mathematical expressions.
@@ -6,8 +5,6 @@ file for the supported mathematical expressions.
 
 
 from node import ExpressionNode as Node, ExpressionLeaf as Leaf
 from node import ExpressionNode as Node, ExpressionLeaf as Leaf
 
 
-import argparse
-
 import os.path
 import os.path
 PYBISON_BUILD = os.path.realpath('build/external/pybison')
 PYBISON_BUILD = os.path.realpath('build/external/pybison')
 EXTERNAL_MODS = os.path.realpath('external')
 EXTERNAL_MODS = os.path.realpath('external')
@@ -21,7 +18,7 @@ from graph_drawing.graph import generate_graph
 
 
 from node import TYPE_OPERATOR, OP_COMMA
 from node import TYPE_OPERATOR, OP_COMMA
 from rules import RULES
 from rules import RULES
-from possibilities import filter_duplicates
+from possibilities import filter_duplicates, pick_suggestion, apply_suggestion
 
 
 
 
 # Check for n-ary operator in child nodes
 # Check for n-ary operator in child nodes
@@ -55,7 +52,7 @@ class Parser(BisonParser):
     # of tokens of the lex script.
     # of tokens of the lex script.
     tokens = ['NUMBER', 'IDENTIFIER',
     tokens = ['NUMBER', 'IDENTIFIER',
               'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW',
               'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW',
-              'LPAREN', 'RPAREN', 'COMMA',
+              'LPAREN', 'RPAREN', 'COMMA', 'HINT', 'REWRITE',
               'NEWLINE', 'QUIT', 'RAISE', 'GRAPH']
               'NEWLINE', 'QUIT', 'RAISE', 'GRAPH']
 
 
     # ------------------------------
     # ------------------------------
@@ -75,11 +72,9 @@ class Parser(BisonParser):
         BisonParser.__init__(self, **kwargs)
         BisonParser.__init__(self, **kwargs)
         self.interactive = kwargs.get('interactive', 0)
         self.interactive = kwargs.get('interactive', 0)
         self.timeout = kwargs.get('timeout', 0)
         self.timeout = kwargs.get('timeout', 0)
-        self.possibilities = []
+        self.possibilities = self.last_possibilities = []
 
 
-    # ------------------------------------------------------------------
-    # override default read method with a version that prompts for input
-    # ------------------------------------------------------------------
+    # Override default read method with a version that prompts for input.
     def read(self, nbytes):
     def read(self, nbytes):
         if self.file == sys.stdin and self.file.closed:
         if self.file == sys.stdin and self.file.closed:
             return ''
             return ''
@@ -90,10 +85,15 @@ class Parser(BisonParser):
             return ''
             return ''
 
 
     def hook_read_before(self):
     def hook_read_before(self):
-        if self.interactive and self.possibilities:
-            print 'possibilities:'
+        if self.possibilities:
+            if self.interactive:  # pragma: nocover
+                print 'possibilities:'
+
             items = filter_duplicates(self.possibilities)
             items = filter_duplicates(self.possibilities)
-            print '  ' + '\n  '.join(map(str, items))
+            self.last_possibilities = self.possibilities
+
+            if self.interactive:  # pragma: nocover
+                print '  ' + '\n  '.join(map(str, items))
 
 
         self.possibilities = []
         self.possibilities = []
 
 
@@ -147,7 +147,7 @@ class Parser(BisonParser):
             if data == data_after:
             if data == data_after:
                 break
                 break
 
 
-            if self.verbose:
+            if self.verbose:  # pragma: nocover
                 print 'hook_read_after() modified the input data:'
                 print 'hook_read_after() modified the input data:'
                 print 'before:', data.replace('\n', '\\n')
                 print 'before:', data.replace('\n', '\\n')
                 print 'after :', data_after.replace('\n', '\\n')
                 print 'after :', data_after.replace('\n', '\\n')
@@ -192,7 +192,7 @@ class Parser(BisonParser):
             # Interactive mode is enabled if the term rewriting system is used
             # Interactive mode is enabled if the term rewriting system is used
             # as a shell. In that case, it is useful that the shell prints the
             # as a shell. In that case, it is useful that the shell prints the
             # output of the evaluation.
             # output of the evaluation.
-            if self.interactive and values[1]:
+            if self.interactive and values[1]:  # pragma: nocover
                 print values[1]
                 print values[1]
 
 
             return values[1]
             return values[1]
@@ -202,12 +202,22 @@ class Parser(BisonParser):
         line : NEWLINE
         line : NEWLINE
              | exp NEWLINE
              | exp NEWLINE
              | debug NEWLINE
              | debug NEWLINE
+             | HINT NEWLINE
+             | REWRITE NEWLINE
              | RAISE NEWLINE
              | RAISE NEWLINE
         """
         """
         if option in [1, 2]:
         if option in [1, 2]:
             return values[0]
             return values[0]
 
 
         if option == 3:
         if option == 3:
+            print pick_suggestion(self.last_possibilities)
+            return
+
+        if option == 4:
+            suggestion = pick_suggestion(self.last_possibilities)
+            return apply_suggestion(suggestion)
+
+        if option == 5:
             raise RuntimeError('on_line: exception raised')
             raise RuntimeError('on_line: exception raised')
 
 
     def on_debug(self, target, option, names, values):
     def on_debug(self, target, option, names, values):
@@ -332,6 +342,8 @@ class Parser(BisonParser):
     "^"       { returntoken(POW); }
     "^"       { returntoken(POW); }
     "/"       { returntoken(DIVIDE); }
     "/"       { returntoken(DIVIDE); }
     ","       { returntoken(COMMA); }
     ","       { returntoken(COMMA); }
+    "?"       { returntoken(HINT); }
+    "@"       { returntoken(REWRITE); }
     "quit"    { yyterminate(); returntoken(QUIT); }
     "quit"    { yyterminate(); returntoken(QUIT); }
     "raise"   { returntoken(RAISE); }
     "raise"   { returntoken(RAISE); }
     "graph"   { returntoken(GRAPH); }
     "graph"   { returntoken(GRAPH); }
@@ -344,39 +356,3 @@ class Parser(BisonParser):
 
 
     yywrap() { return(1); }
     yywrap() { return(1); }
     """
     """
-
-
-def get_args():
-    parser = argparse.ArgumentParser(prog='parser', description=__doc__)
-
-    parser.add_argument('--debug', '-d', action='store_true',
-            default=False,
-            help='Enable debug mode in bison and flex.')
-    parser.add_argument('--verbose', '-v', action='store_true',
-            default=False,
-            help='Enable verbose output messages (printed to stdout).')
-    parser.add_argument('--keepfiles', '-k', action='store_true',
-            default=False,
-            help='Keep temporary generated bison and lex files.')
-    parser.add_argument('--batch', '-b', action='store_true', default=False,
-            help='Disable interactive mode and execute expressions in batch' \
-                 ' mode.')
-
-    return parser.parse_args()
-
-
-def main():
-    args = get_args()
-    interactive = not args.batch and sys.stdin.isatty()
-
-    p = Parser(verbose=args.verbose,
-               keepfiles=args.keepfiles,
-               interactive=interactive)
-
-    node = p.run(debug=args.debug)
-
-    # Clear the line, when the shell exits.
-    if interactive:
-        print
-
-    return node

+ 10 - 0
src/possibilities.py

@@ -36,3 +36,13 @@ def filter_duplicates(items):
             unique.append(item)
             unique.append(item)
 
 
     return unique
     return unique
+
+
+def pick_suggestion(possibilities):
+    # TODO: pick the best suggestion.
+    suggestion = 0
+    return possibilities[suggestion]
+
+
+def apply_suggestion(suggestion):
+    return suggestion.handler(suggestion.root, suggestion.args)