Jelajahi Sumber

Added new syntax for derivatives to the parser.

Taddeus Kroes 14 tahun lalu
induk
melakukan
9e395dc2f9
2 mengubah file dengan 35 tambahan dan 5 penghapusan
  1. 26 3
      src/parser.py
  2. 9 2
      tests/test_parser.py

+ 26 - 3
src/parser.py

@@ -15,7 +15,8 @@ from pybison import BisonParser, BisonSyntaxError
 from graph_drawing.graph import generate_graph
 
 from node import ExpressionNode as Node, ExpressionLeaf as Leaf, OP_MAP, \
-        TOKEN_MAP, TYPE_OPERATOR, OP_COMMA, OP_NEG, OP_MUL, OP_DIV, Scope, PI
+        OP_DERIV, TOKEN_MAP, TYPE_OPERATOR, OP_COMMA, OP_NEG, OP_MUL, OP_DIV, \
+        Scope, PI
 from rules import RULES
 from strategy import pick_suggestion
 from possibilities import filter_duplicates, apply_suggestion
@@ -57,7 +58,8 @@ class Parser(BisonParser):
     # TODO: add a runtime check to verify that this token list match the list
     # of tokens of the lex script.
     tokens = ['NUMBER', 'IDENTIFIER', 'NEWLINE', 'QUIT', 'RAISE', 'GRAPH',
-              'LPAREN', 'RPAREN', 'FUNCTION'] \
+              'LPAREN', 'RPAREN', 'FUNCTION', 'LBRACKET', 'RBRACKET', \
+              'APOSTROPH'] \
              + filter(lambda t: t != 'FUNCTION', TOKEN_MAP.values())
 
     # ------------------------------
@@ -331,6 +333,7 @@ class Parser(BisonParser):
             | unary
             | binary
             | nary
+            | derivative
         """
         #    | concat
 
@@ -345,12 +348,29 @@ class Parser(BisonParser):
         if option == 2:  # rule: LPAREN exp RPAREN
             return values[1]
 
-        if option in [3, 4, 5]:  # rule: unary | binary | nary
+        if option in [3, 4, 5, 6]:  # rule: unary | binary | nary | derivative
             return values[0]
 
         raise BisonSyntaxError('Unsupported option %d in target "%s".'
                                % (option, target))  # pragma: nocover
 
+    def on_derivative(self, target, option, names, values):
+        """
+        derivative : LBRACKET exp RBRACKET APOSTROPH
+                   | derivative APOSTROPH
+        """
+
+        op = [k for k, v in OP_MAP.iteritems() if v == OP_DERIV][0]
+
+        if option == 0:  # rule: LBRACKET exp RBRACKET APOSTROPH
+            return Node(op, values[1])
+
+        if option == 1:  # rule: derivative APOSTROPH
+            return Node(op, values[0])
+
+        raise BisonSyntaxError('Unsupported option %d in target "%s".'
+                               % (option, target))  # pragma: nocover
+
     def on_unary(self, target, option, names, values):
         """
         unary : MINUS exp %prec NEG
@@ -482,6 +502,9 @@ class Parser(BisonParser):
 
     [ \t\v\f] { }
     [\n]      { yycolumn = 0; returntoken(NEWLINE); }
+    "["       { returntoken(LBRACKET); }
+    "]"       { returntoken(RBRACKET); }
+    "'"       { returntoken(APOSTROPH); }
     .         { printf("unknown char %c ignored.\n", yytext[0]); }
 
     %%

+ 9 - 2
tests/test_parser.py

@@ -6,6 +6,7 @@ from src.node import ExpressionNode as Node, ExpressionLeaf as Leaf
 from tests.parser import ParserWrapper, run_expressions, line, graph
 from tests.rulestestcase import tree
 from src.rules.goniometry import sin, cos
+from src.rules.derivatives import der
 
 
 class TestParser(unittest.TestCase):
@@ -47,12 +48,18 @@ class TestParser(unittest.TestCase):
         self.assertEqual(tree('-(a / b)'), (-a) / b)
 
     def test_functions(self):
-        root, x = tree('sin x, x')
+        x = tree('x')
 
-        self.assertEqual(root, sin(x))
+        self.assertEqual(tree('sin x'), sin(x))
+        self.assertEqual(tree('sin(x)'), sin(x))
         self.assertEqual(tree('sin x ^ 2'), sin(x) ** 2)
         self.assertEqual(tree('sin(x) ^ 2'), sin(x) ** 2)
         self.assertEqual(tree('sin (x) ^ 2'), sin(x) ** 2)
         self.assertEqual(tree('sin(x ^ 2)'), sin(x ** 2))
         self.assertEqual(tree('sin cos x'), sin(cos(x)))
         self.assertEqual(tree('sin cos x ^ 2'), sin(cos(x)) ** 2)
+
+    def test_derivative(self):
+        x = tree('x')
+
+        self.assertEqual(tree('[x]\''), der(x))