Ver Fonte

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 há 14 anos atrás
pai
commit
04ffd70216
4 ficheiros alterados com 88 adições e 67 exclusões
  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
+"""
+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():
-    import os
     try:
         import readline
     except ImportError:
@@ -19,7 +28,48 @@ def init_readline():
     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__':
-    from src.parser import main
     init_readline()
     main()

+ 0 - 15
src/node.py

@@ -128,12 +128,6 @@ class ExpressionNode(Node, ExpressionBase):
     def graph(self):  # pragma: nocover
         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):
         """
         Extract polynome properties into tuple format: (coefficient, root,
@@ -219,12 +213,3 @@ class ExpressionLeaf(Leaf, ExpressionBase):
         """
         # rule: 1 * r ^ 1 -> (1, r, 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
 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
 
-import argparse
-
 import os.path
 PYBISON_BUILD = os.path.realpath('build/external/pybison')
 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 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
@@ -55,7 +52,7 @@ class Parser(BisonParser):
     # of tokens of the lex script.
     tokens = ['NUMBER', 'IDENTIFIER',
               'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW',
-              'LPAREN', 'RPAREN', 'COMMA',
+              'LPAREN', 'RPAREN', 'COMMA', 'HINT', 'REWRITE',
               'NEWLINE', 'QUIT', 'RAISE', 'GRAPH']
 
     # ------------------------------
@@ -75,11 +72,9 @@ class Parser(BisonParser):
         BisonParser.__init__(self, **kwargs)
         self.interactive = kwargs.get('interactive', 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):
         if self.file == sys.stdin and self.file.closed:
             return ''
@@ -90,10 +85,15 @@ class Parser(BisonParser):
             return ''
 
     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)
-            print '  ' + '\n  '.join(map(str, items))
+            self.last_possibilities = self.possibilities
+
+            if self.interactive:  # pragma: nocover
+                print '  ' + '\n  '.join(map(str, items))
 
         self.possibilities = []
 
@@ -147,7 +147,7 @@ class Parser(BisonParser):
             if data == data_after:
                 break
 
-            if self.verbose:
+            if self.verbose:  # pragma: nocover
                 print 'hook_read_after() modified the input data:'
                 print 'before:', data.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
             # as a shell. In that case, it is useful that the shell prints the
             # output of the evaluation.
-            if self.interactive and values[1]:
+            if self.interactive and values[1]:  # pragma: nocover
                 print values[1]
 
             return values[1]
@@ -202,12 +202,22 @@ class Parser(BisonParser):
         line : NEWLINE
              | exp NEWLINE
              | debug NEWLINE
+             | HINT NEWLINE
+             | REWRITE NEWLINE
              | RAISE NEWLINE
         """
         if option in [1, 2]:
             return values[0]
 
         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')
 
     def on_debug(self, target, option, names, values):
@@ -332,6 +342,8 @@ class Parser(BisonParser):
     "^"       { returntoken(POW); }
     "/"       { returntoken(DIVIDE); }
     ","       { returntoken(COMMA); }
+    "?"       { returntoken(HINT); }
+    "@"       { returntoken(REWRITE); }
     "quit"    { yyterminate(); returntoken(QUIT); }
     "raise"   { returntoken(RAISE); }
     "graph"   { returntoken(GRAPH); }
@@ -344,39 +356,3 @@ class Parser(BisonParser):
 
     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)
 
     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)