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

Interactive parser state is not changed by parser hooks anymore, but separated in functions.

Taddeus Kroes пре 14 година
родитељ
комит
57bc805cfa
2 измењених фајлова са 97 додато и 47 уклоњено
  1. 96 46
      src/parser.py
  2. 1 1
      src/possibilities.py

+ 96 - 46
src/parser.py

@@ -21,7 +21,7 @@ from node import ExpressionBase, ExpressionNode as Node, \
         OP_INT_INDEF, OP_ABS, OP_NEG, negation_to_node
 from rules import RULES
 from rules.utils import find_variable
-from strategy import pick_suggestion
+#from strategy import sort_possiblities
 from possibilities import filter_duplicates, apply_suggestion
 
 import Queue
@@ -58,6 +58,34 @@ def find_integration_variable(exp):
     return exp, find_variable(exp)
 
 
+def find_possibilities(node, depth=0):
+    """
+    Find all possibilities inside a node and return them in a list.
+    """
+    p = []
+    handlers = []
+
+    # Add negation handlers
+    if node.negated:
+        handlers.extend(RULES[OP_NEG])
+
+    if not node.is_leaf:
+        # Traverse through child nodes first using postorder traversal
+        for child in node:
+            p.extend(find_possibilities(child, depth + 1))
+
+        # Add operator-specific handlers
+        if node.op in RULES:
+            handlers.extend(RULES[node.op])
+
+    # Run handlers
+    for handler in handlers:
+        possibilities = [(pos, depth) for pos in handler(node)]
+        p.extend(possibilities)
+
+    return p
+
+
 class Parser(BisonParser):
     """
     Implements the calculator parser. Grammar rules are defined in the method
@@ -93,7 +121,6 @@ class Parser(BisonParser):
         ('left', ('MINUS', 'PLUS', 'NEG')),
         ('left', ('TIMES', 'DIVIDE')),
         ('right', ('FUNCTION', )),
-        #('left', ('NEG', )),
         ('right', ('POW', )),
         ('left', ('SUB', )),
         ('right', ('FUNCTION_LPAREN', )),
@@ -239,50 +266,79 @@ class Parser(BisonParser):
         return data
 
     def hook_handler(self, target, option, names, values, retval):
-        if target in ['exp', 'line', 'input'] \
-                or not isinstance(retval, ExpressionBase):
-            return retval
+        return retval
 
-        if not retval.negated and retval.type != TYPE_OPERATOR:
-            return retval
+        #if target in ['exp', 'line', 'input'] \
+        #        or not isinstance(retval, ExpressionBase):
+        #    return retval
 
-        if retval.negated:
-            handlers = RULES[OP_NEG]
-        elif retval.type == TYPE_OPERATOR and retval.op in RULES:
-            handlers = RULES[retval.op]
-        else:
-            return retval
+        #if not retval.negated and retval.type != TYPE_OPERATOR:
+        #    return retval
 
-        for handler in handlers:
-            possibilities = handler(retval)
-            self.possibilities.extend(possibilities)
+        #if retval.negated:
+        #    handlers = RULES[OP_NEG]
+        #elif retval.type == TYPE_OPERATOR and retval.op in RULES:
+        #    handlers = RULES[retval.op]
+        #else:
+        #    return retval
 
-        return retval
+        #for handler in handlers:
+        #    possibilities = handler(retval)
+        #    self.possibilities.extend(possibilities)
+
+        #return retval
+
+    def find_possibilities(self):
+        if not self.root_node:
+            raise RuntimeError('No expression')
+
+        p = find_possibilities(self.root_node)
+        #sort_possiblities(p)
+        self.root_possibilities = [pos for pos, depth in p]
 
     def display_hint(self):
-        print pick_suggestion(self.last_possibilities)
+        self.find_possibilities()
+
+        if self.root_possibilities:
+            print self.root_possibilities[0]
+        else:
+            print 'No further reduction is possible.'
 
     def display_possibilities(self):
-        if self.last_possibilities:
-            print '\n'.join(map(str, self.last_possibilities))
+        self.find_possibilities()
+
+        if self.root_possibilities:
+            print '\n'.join(map(str, self.root_possibilities))
 
     def rewrite(self):
-        suggestion = pick_suggestion(self.last_possibilities)
+        self.find_possibilities()
 
-        if self.verbose:
-            print 'applying suggestion:', suggestion
+        if not self.root_possibilities:
+            return False
 
-        if not suggestion:
-            return self.root_node
+        suggestion = self.root_possibilities[0]
+
+        if self.verbose:
+            print 'Applying suggestion:', suggestion
 
         expression = apply_suggestion(self.root_node, suggestion)
 
         if self.verbose:
-            print 'After application, expression=', expression
+            print 'After application:', expression
+
+        self.root_node = expression
+
+        return True
 
-        self.read_queue.put_nowait(str(expression))
+    def rewrite_all(self):
+        i = 0
+
+        while self.rewrite():
+            i += 1
 
-        return expression
+            if i > 100:
+                print 'Too many rewrite steps, aborting...'
+                break
 
     #def hook_run(self, filename, retval):
     #    return retval
@@ -304,7 +360,6 @@ class Parser(BisonParser):
         """
         input :
               | input line
-              | input REWRITE NEWLINE
         """
         if option == 1:
             # Interactive mode is enabled if the term rewriting system is used
@@ -315,10 +370,6 @@ class Parser(BisonParser):
 
             return values[1]
 
-        if option == 2:  # rule: input REWRITE NEWLINE
-            self.root_node = self.rewrite()
-            return self.root_node
-
     def on_line(self, target, option, names, values):
         """
         line : NEWLINE
@@ -326,20 +377,11 @@ class Parser(BisonParser):
              | debug NEWLINE
              | HINT NEWLINE
              | POSSIBILITIES NEWLINE
+             | REWRITE NEWLINE
+             | REWRITE_ALL NEWLINE
              | RAISE NEWLINE
         """
-        if option == 1:  # rule: EXP NEWLINE
-            self.root_node = values[0]
-
-            # Clear list of last possibilities when current expression has no
-            # possibilities. Otherwise, an invalid expression gets the last
-            # possibilities of a valid expression.
-            if not self.possibilities:
-                self.last_possibilities = []
-
-            return values[0]
-
-        if option == 2:  # rule: DEBUG NEWLINE
+        if option in (1, 2):  # rule: {exp,debug} NEWLINE
             self.root_node = values[0]
             return values[0]
 
@@ -351,7 +393,15 @@ class Parser(BisonParser):
             self.display_possibilities()
             return
 
-        if option == 5:
+        if option == 5:  # rule: REWRITE NEWLINE
+            self.rewrite()
+            return self.root_node
+
+        if option == 6:  # rule: REWRITE_ALL NEWLINE
+            self.rewrite_all()
+            return self.root_node
+
+        if option == 7:
             raise RuntimeError('on_line: exception raised')
 
     def on_debug(self, target, option, names, values):

+ 1 - 1
src/possibilities.py

@@ -18,7 +18,7 @@ class Possibility(object):
         if self.handler in MESSAGES:
             return MESSAGES[self.handler].format(self.root, *self.args)
 
-        return self.__repr__()
+        return repr(self)
 
     def __repr__(self):
         return '<Possibility root="%s" handler=%s args=%s>' \