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

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 rules import RULES
 from possibilities import filter_duplicates, pick_suggestion, apply_suggestion
 from possibilities import filter_duplicates, pick_suggestion, apply_suggestion
 
 
+import Queue
+
 
 
 # Check for n-ary operator in child nodes
 # Check for n-ary operator in child nodes
 def combine(op, op_type, *nodes):
 def combine(op, op_type, *nodes):
@@ -74,16 +76,31 @@ class Parser(BisonParser):
         self.timeout = kwargs.get('timeout', 0)
         self.timeout = kwargs.get('timeout', 0)
         self.possibilities = self.last_possibilities = []
         self.possibilities = self.last_possibilities = []
 
 
+        self.read_buffer = ''
+        self.read_queue = Queue.Queue()
+
     # 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 ''
 
 
+        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:
         try:
-            return raw_input('>>> ' if self.interactive else '') + '\n'
+            read_buffer = raw_input('>>> ' if self.interactive else '') + '\n'
         except EOFError:
         except EOFError:
             return ''
             return ''
 
 
+        self.read_buffer = read_buffer[nbytes:]
+        return read_buffer[:nbytes]
+
     def hook_read_before(self):
     def hook_read_before(self):
         if self.possibilities:
         if self.possibilities:
             if self.interactive:  # pragma: nocover
             if self.interactive:  # pragma: nocover
@@ -95,14 +112,17 @@ class Parser(BisonParser):
             if self.interactive:  # pragma: nocover
             if self.interactive:  # pragma: nocover
                 print '  ' + '\n  '.join(map(str, items))
                 print '  ' + '\n  '.join(map(str, items))
 
 
-        self.possibilities = []
-
     def hook_read_after(self, data):
     def hook_read_after(self, data):
         """
         """
         This hook will be called when the read() method returned. The 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
         argument points to the data read by the read() method. This hook
         function should return the data to be used by the parser.
         function should return the data to be used by the parser.
         """
         """
+        if not data.strip():
+            return data
+
+        self.possibilities = []
+
         import re
         import re
 
 
         # TODO: remove this quick preprocessing hack. This hack enables
         # TODO: remove this quick preprocessing hack. This hack enables
@@ -187,7 +207,6 @@ class Parser(BisonParser):
         input :
         input :
               | input line
               | input line
         """
         """
-
         if option == 1:
         if option == 1:
             # 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
@@ -207,20 +226,22 @@ class Parser(BisonParser):
              | REWRITE NEWLINE
              | REWRITE NEWLINE
              | RAISE NEWLINE
              | RAISE NEWLINE
         """
         """
-        if option in [1, 2]:
+        if option in [1, 2]:  # rule: EXP NEWLINE | DEBUG NEWLINE
             return values[0]
             return values[0]
 
 
-        if option == 3:
+        if option == 3:  # rule: HINT NEWLINE
             print pick_suggestion(self.last_possibilities)
             print pick_suggestion(self.last_possibilities)
             return
             return
 
 
-        if option == 4:
+        if option == 4:  # rule: POSSIBILITIES NEWLINE
             print '\n'.join(map(str, self.last_possibilities))
             print '\n'.join(map(str, self.last_possibilities))
             return
             return
 
 
-        if option == 5:
+        if option == 5:  # rule: REWRITE NEWLINE
             suggestion = pick_suggestion(self.last_possibilities)
             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:
         if option == 6:
             raise RuntimeError('on_line: exception raised')
             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 src.rules.numerics import add_numerics
 from tests.test_rules_poly import tree
 from tests.test_rules_poly import tree
 
 
+from src.parser import Parser
+from tests.parser import ParserWrapper
+
 
 
 def dummy_handler(root, args):  # pragma: nocover
 def dummy_handler(root, args):  # pragma: nocover
     pass
     pass
@@ -36,6 +39,36 @@ class TestPossibilities(unittest.TestCase):
         assert self.p0 == P(self.n, dummy_handler, (self.l1, self.l2))
         assert self.p0 == P(self.n, dummy_handler, (self.l1, self.l2))
         assert self.p0 != self.p1
         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):
     def test_filter_duplicates(self):
         a, b = ab = tree('a + b')
         a, b = ab = tree('a + b')
         p0 = P(a, dummy_handler, (1, 2))
         p0 = P(a, dummy_handler, (1, 2))