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

Merge branch 'master' of kompiler.org:trs

Taddeus Kroes пре 14 година
родитељ
комит
2d9ca51e11
2 измењених фајлова са 63 додато и 9 уклоњено
  1. 30 9
      src/parser.py
  2. 33 0
      tests/test_possibilities.py

+ 30 - 9
src/parser.py

@@ -20,6 +20,8 @@ from node import TYPE_OPERATOR, OP_COMMA
 from rules import RULES
 from possibilities import filter_duplicates, pick_suggestion, apply_suggestion
 
+import Queue
+
 
 # Check for n-ary operator in child nodes
 def combine(op, op_type, *nodes):
@@ -74,16 +76,31 @@ class Parser(BisonParser):
         self.timeout = kwargs.get('timeout', 0)
         self.possibilities = self.last_possibilities = []
 
+        self.read_buffer = ''
+        self.read_queue = Queue.Queue()
+
     # 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 ''
 
+        if not self.read_buffer and not self.read_queue.empty():
+            self.read_buffer = self.read_queue.get_nowait() + '\n'
+
+        if self.read_buffer:
+            read_buffer = self.read_buffer[:nbytes]
+
+            self.read_buffer = self.read_buffer[nbytes:]
+            return read_buffer
+
         try:
-            return raw_input('>>> ' if self.interactive else '') + '\n'
+            read_buffer = raw_input('>>> ' if self.interactive else '') + '\n'
         except EOFError:
             return ''
 
+        self.read_buffer = read_buffer[nbytes:]
+        return read_buffer[:nbytes]
+
     def hook_read_before(self):
         if self.possibilities:
             if self.interactive:  # pragma: nocover
@@ -95,14 +112,17 @@ class Parser(BisonParser):
             if self.interactive:  # pragma: nocover
                 print '  ' + '\n  '.join(map(str, items))
 
-        self.possibilities = []
-
     def hook_read_after(self, data):
         """
         This hook will be called when the read() method returned. The data
         argument points to the data read by the read() method. This hook
         function should return the data to be used by the parser.
         """
+        if not data.strip():
+            return data
+
+        self.possibilities = []
+
         import re
 
         # TODO: remove this quick preprocessing hack. This hack enables
@@ -187,7 +207,6 @@ class Parser(BisonParser):
         input :
               | input line
         """
-
         if option == 1:
             # 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
@@ -207,20 +226,22 @@ class Parser(BisonParser):
              | REWRITE NEWLINE
              | RAISE NEWLINE
         """
-        if option in [1, 2]:
+        if option in [1, 2]:  # rule: EXP NEWLINE | DEBUG NEWLINE
             return values[0]
 
-        if option == 3:
+        if option == 3:  # rule: HINT NEWLINE
             print pick_suggestion(self.last_possibilities)
             return
 
-        if option == 4:
+        if option == 4:  # rule: POSSIBILITIES NEWLINE
             print '\n'.join(map(str, self.last_possibilities))
             return
 
-        if option == 5:
+        if option == 5:  # rule: REWRITE NEWLINE
             suggestion = pick_suggestion(self.last_possibilities)
-            return apply_suggestion(suggestion)
+            expression = apply_suggestion(suggestion)
+            self.read_queue.put_nowait(str(expression))
+            return expression
 
         if option == 6:
             raise RuntimeError('on_line: exception raised')

+ 33 - 0
tests/test_possibilities.py

@@ -4,6 +4,9 @@ from src.possibilities import MESSAGES, Possibility as P, filter_duplicates
 from src.rules.numerics import add_numerics
 from tests.test_rules_poly import tree
 
+from src.parser import Parser
+from tests.parser import ParserWrapper
+
 
 def dummy_handler(root, args):  # pragma: nocover
     pass
@@ -36,6 +39,36 @@ class TestPossibilities(unittest.TestCase):
         assert self.p0 == P(self.n, dummy_handler, (self.l1, self.l2))
         assert self.p0 != self.p1
 
+    def test_multiple_input(self):
+        parser = ParserWrapper(Parser)
+        parser.run(['1+2', '3+4'])
+        possibilities = parser.parser.possibilities
+        self.assertEqual('\n'.join([repr(pos) for pos in possibilities]),
+                    '<Possibility root="3 + 4" handler=add_numerics' \
+                    ' args=(3, 4, 3, 4)>')
+
+    def test_multiple_runs(self):
+        parser = ParserWrapper(Parser)
+        parser.run(['1+2'])
+        possibilities = parser.parser.possibilities
+        self.assertEqual('\n'.join([repr(pos) for pos in possibilities]),
+                    '<Possibility root="1 + 2" handler=add_numerics' \
+                    ' args=(1, 2, 1, 2)>')
+
+        # Keep previous possibilities (skip whitespace lines)
+        parser.run(['', ' '])
+        possibilities = parser.parser.possibilities
+        self.assertEqual('\n'.join([repr(pos) for pos in possibilities]),
+                    '<Possibility root="1 + 2" handler=add_numerics' \
+                    ' args=(1, 2, 1, 2)>')
+
+        # Overwrite previous possibilities with new ones
+        parser.run(['3+4'])
+        possibilities = parser.parser.possibilities
+        self.assertEqual('\n'.join([repr(pos) for pos in possibilities]),
+                    '<Possibility root="3 + 4" handler=add_numerics' \
+                    ' args=(3, 4, 3, 4)>')
+
     def test_filter_duplicates(self):
         a, b = ab = tree('a + b')
         p0 = P(a, dummy_handler, (1, 2))