Commit 196a602c authored by Taddeus Kroes's avatar Taddeus Kroes

Added notation for absolute value to the parser.

parent 1952f7ba
......@@ -21,35 +21,36 @@ TYPE_FLOAT = 8
# Unary
OP_NEG = 1
OP_ABS = 2
# Binary
OP_ADD = 2
OP_SUB = 3
OP_MUL = 4
OP_DIV = 5
OP_POW = 6
OP_SUBSCRIPT = 7
OP_ADD = 3
OP_SUB = 4
OP_MUL = 5
OP_DIV = 6
OP_POW = 7
OP_SUBSCRIPT = 8
# N-ary (functions)
OP_INT = 8
OP_INT_INDEF = 9
OP_COMMA = 10
OP_SQRT = 11
OP_DER = 12
OP_LOG = 13
OP_INT = 9
OP_INT_INDEF = 10
OP_COMMA = 11
OP_SQRT = 12
OP_DER = 13
OP_LOG = 14
# Goniometry
OP_SIN = 14
OP_COS = 15
OP_TAN = 16
OP_SIN = 15
OP_COS = 16
OP_TAN = 17
OP_SOLVE = 17
OP_EQ = 18
OP_SOLVE = 18
OP_EQ = 19
OP_POSSIBILITIES = 19
OP_HINT = 20
OP_REWRITE_ALL = 21
OP_REWRITE = 22
OP_POSSIBILITIES = 20
OP_HINT = 21
OP_REWRITE_ALL = 22
OP_REWRITE = 23
# Special identifiers
PI = 'pi'
......@@ -94,6 +95,7 @@ OP_MAP = {
OP_VALUE_MAP = dict([(v, k) for k, v in OP_MAP.iteritems()])
OP_MAP['ln'] = OP_LOG
OP_VALUE_MAP[OP_INT_INDEF] = 'indef'
OP_VALUE_MAP[OP_ABS] = 'abs'
TOKEN_MAP = {
OP_COMMA: 'COMMA',
......@@ -319,6 +321,9 @@ class ExpressionNode(Node, ExpressionBase):
return '[%s]%s%s' % (F, lbnd, ubnd)
if self.op == OP_ABS:
return '|%s|' % children[0]
def __str__(self): # pragma: nocover
return generate_line(self)
......
......@@ -18,7 +18,7 @@ from node import ExpressionBase, ExpressionNode as Node, \
ExpressionLeaf as Leaf, OP_MAP, OP_DER, TOKEN_MAP, TYPE_OPERATOR, \
OP_COMMA, OP_NEG, OP_MUL, OP_DIV, OP_POW, OP_LOG, OP_ADD, Scope, E, \
DEFAULT_LOGARITHM_BASE, OP_VALUE_MAP, SPECIAL_TOKENS, OP_INT, \
OP_INT_INDEF
OP_INT_INDEF, OP_ABS
from rules import RULES
from rules.utils import find_variable
from strategy import pick_suggestion
......@@ -78,7 +78,7 @@ class Parser(BisonParser):
# of tokens of the lex script.
tokens = ['NUMBER', 'IDENTIFIER', 'NEWLINE', 'QUIT', 'RAISE', 'GRAPH',
'LPAREN', 'RPAREN', 'FUNCTION', 'FUNCTION_LPAREN', 'LBRACKET',
'RBRACKET', 'PRIME', 'DERIVATIVE'] \
'RBRACKET', 'PIPE', 'PRIME', 'DERIVATIVE'] \
+ filter(lambda t: t != 'FUNCTION', TOKEN_MAP.values())
# ------------------------------
......@@ -180,16 +180,16 @@ class Parser(BisonParser):
# - "4a" with "4*a".
# - "a4" with "a^4".
pattern = ('(?:(\))\s*(\(|\[)' # )( -> ) * (
pattern = ('(?:(\))\s*([([])' # )( -> ) * (
# )[ -> ) * [
+ '|([\x00-\x09\x0b-\x19a-z0-9])\s*(\(|\[)' # a( -> a * (
+ '|([\x00-\x09\x0b-\x19a-z0-9])\s*([([])' # a( -> a * (
# a[ -> a * [
+ '|(\))\s*([\x00-\x09\x0b-\x19a-z0-9])' # )a -> ) * a
+ '|([\x00-\x09\x0b-\x19a-z])\s*'
+ '([\x00-\x09\x0b-\x19a-z])' # ab -> a * b
+ '|([0-9])\s*([\x00-\x09\x0b-\x19a-z])' # 4a -> 4 * a
+ '|([\x00-\x09\x0b-\x19a-z])([0-9])' # a4 -> a ^ 4
+ '|([\x00-\x09\x0b-\x19a-z0-9])(\s+[0-9]))' # a 4 -> a * 4,
+ '|([\x00-\x09\x0b-\x19a-z0-9])(\s+[0-9]))' # a 4 -> a * 4
# 4 4 -> 4 * 4
)
......@@ -399,6 +399,7 @@ class Parser(BisonParser):
| INTEGRAL exp
| integral_bounds TIMES exp %prec INTEGRAL
| LBRACKET exp RBRACKET lbnd ubnd
| PIPE exp PIPE
"""
if option == 0: # rule: NEG exp
......@@ -464,6 +465,9 @@ class Parser(BisonParser):
if option == 7: # rule: LBRACKET exp RBRACKET lbnd ubnd
return Node(OP_INT_INDEF, values[1], values[3], values[4])
if option == 8: # rule: PIPE exp PIPE
return Node(OP_ABS, values[1])
raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover
......@@ -633,6 +637,7 @@ class Parser(BisonParser):
"[" { returntoken(LBRACKET); }
"]" { returntoken(RBRACKET); }
"'" { returntoken(PRIME); }
"|" { returntoken(PIPE); }
log_([0-9]+|[a-zA-Z])"*(" { returntoken(FUNCTION_LPAREN); }
log_([0-9]+|[a-zA-Z])"*" { returntoken(FUNCTION); }
""" + operators + r"""
......
from ..node import ExpressionNode as N, ExpressionLeaf as L, OP_MUL, OP_DIV, \
INFINITY
INFINITY, OP_ABS
def greatest_common_divisor(a, b):
......@@ -133,3 +133,10 @@ def infinity():
Return an infinity leaf node.
"""
return L(INFINITY)
def absolute(exp):
"""
Put an 'absolute value' operator on top of the given expression.
"""
return N(OP_ABS, exp)
......@@ -10,6 +10,7 @@ from src.rules.goniometry import sin, cos
from src.rules.derivatives import der
from src.rules.logarithmic import log, ln
from src.rules.integrals import integral, indef
from src.rules.utils import absolute
class TestParser(unittest.TestCase):
......@@ -51,6 +52,14 @@ class TestParser(unittest.TestCase):
self.assertEqual(tree('2(a + b)'), tree('2 * (a + b)'))
self.assertEqual(tree('(a + b)2'), tree('(a + b) * 2'))
self.assertEqual(tree('(a)(b)'), tree('(a) * (b)'))
self.assertEqual(tree('(a)[b]\''), tree('(a) * [b]\''))
# FIXME: self.assertEqual(tree('(a)|b|'), tree('(a) * |b|'))
# FIXME: self.assertEqual(tree('|a|(b)'), tree('|a| * (b)'))
# FIXME: self.assertEqual(tree('a|b|'), tree('a * |b|'))
# FIXME: self.assertEqual(tree('|a|b'), tree('|a| * b'))
def test_moved_negation(self):
a, b = tree('a,b')
......@@ -128,3 +137,9 @@ class TestParser(unittest.TestCase):
x2, a, b = tree('x ^ 2, a, b')
self.assertEqual(tree('[x ^ 2]_a^b'), indef(x2, a, b))
def test_absolute_value(self):
x = tree('x')
self.assertEqual(tree('|x|'), absolute(x))
self.assertEqual(tree('|x2|'), absolute(x ** 2))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment