From 313e3a4efc2c9a3919cfc4373d54f25c0e7f827e Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Wed, 7 Mar 2018 16:26:06 +0300 Subject: [PATCH] - is now a unary operator --- mapytex/calculus/core/evaluate.py | 27 +++++--- mapytex/calculus/core/operator.py | 12 +++- mapytex/calculus/core/str2.py | 100 ++++++++++++++++++++++++++++-- mapytex/calculus/core/tree.py | 4 +- 4 files changed, 122 insertions(+), 21 deletions(-) diff --git a/mapytex/calculus/core/evaluate.py b/mapytex/calculus/core/evaluate.py index 3e2f75a..f16f125 100644 --- a/mapytex/calculus/core/evaluate.py +++ b/mapytex/calculus/core/evaluate.py @@ -12,6 +12,9 @@ Evaluating a binary tree from .operator import OPERATORS +class ComputeError(Exception): + pass + def compute(node, left_v, right_v): """ Computing a node @@ -20,22 +23,26 @@ def compute(node, left_v, right_v): >>> compute("+", 1, 2) 3 - >>> compute("-", 1, 2) - -1 >>> compute("-", None, 2) -2 - + >>> compute("-", 1, 2) + Traceback (most recent call last): + ... + mapytex.calculus.core.evaluate.ComputeError: left_v need to be None for operator with arity 1 """ op = OPERATORS[node] lv = left_v rv = right_v - if lv is None: - return op["_operate"](rv)() - - try: - return op["operate"](lv)(rv) - except NotImplemented: - return op["roperate"](rv)(lv) + if op['arity'] == 1: + if lv is None: + return op["operate"](rv)() + else: + raise ComputeError("left_v need to be None for operator with arity 1") + else: + try: + return op["operate"](lv)(rv) + except NotImplemented: + return op["roperate"](rv)(lv) diff --git a/mapytex/calculus/core/operator.py b/mapytex/calculus/core/operator.py index 5cac730..597699e 100644 --- a/mapytex/calculus/core/operator.py +++ b/mapytex/calculus/core/operator.py @@ -6,29 +6,35 @@ # # Distributed under terms of the MIT license. +class OperatorError(Exception): + pass + OPERATORS = { "+": {'repr': "+", + 'arity': 2, 'precedence': 0, 'operate': lambda x: x.__getattribute__("__add__"), 'roperate': lambda x: x.__getattribute__("__radd__"), }, "-": {'repr': "-", + 'arity': 1, 'precedence': 1, - '_operate': lambda x: x.__getattribute__("__neg__"), - 'operate': lambda x: x.__getattribute__("__sub__"), - 'roperate': lambda x: x.__getattribute__("__rsub__"), + 'operate': lambda x: x.__getattribute__("__neg__"), }, "*": {'repr': "*", + 'arity': 2, 'precedence': 2, 'operate': lambda x: x.__getattribute__("__mul__"), 'roperate': lambda x: x.__getattribute__("__rmul__"), }, "/": {'repr': "/", + 'arity': 2, 'precedence': 3, 'operate': lambda x: x.__getattribute__("__div__"), 'roperate': lambda x: x.__getattribute__("__rdiv__"), }, "^": {'repr': "^", + 'arity': 2, 'precedence': 4, 'operate': lambda x: x.__getattribute__("__pow__"), 'roperate': lambda x: x.__getattribute__("__rpow__"), diff --git a/mapytex/calculus/core/str2.py b/mapytex/calculus/core/str2.py index 69fef09..3184d0e 100644 --- a/mapytex/calculus/core/str2.py +++ b/mapytex/calculus/core/str2.py @@ -17,6 +17,10 @@ from .operator import is_operator __all__ = ["str2", ] +class ParsingError(Exception): + pass + + def maybe_it_is(cara): """ Return a function which return @@ -417,13 +421,38 @@ def lookforNumbers(target): ... str2list.send(i) Traceback (most recent call last): ... - ValueError: Can't build a number with 2 dots (current is 12.3) + mapytex.calculus.core.str2.ParsingError: Can't build a number with 2 dots (current is 12.3) >>> str2list = lookforNumbers(list_sink) >>> for i in ".34*67": ... a = str2list.send(i) Traceback (most recent call last): ... - ValueError: Can't build a number starting with a dot + mapytex.calculus.core.str2.ParsingError: Can't build a number starting with a dot + + >>> str2list = lookforNumbers(list_sink) + >>> for i in "12-34": + ... str2list.send(i) + >>> a = str2list.throw(STOOOP) + >>> print(a) + [12, '+', -34] + >>> str2list = lookforNumbers(list_sink) + >>> for i in "-12+34": + ... str2list.send(i) + >>> a = str2list.throw(STOOOP) + >>> print(a) + [-12, '+', 34] + >>> str2list = lookforNumbers(list_sink) + >>> for i in "3-1.2": + ... str2list.send(i) + >>> a = str2list.throw(STOOOP) + >>> print(a) + [3, '+', Decimal('-1.2')] + >>> str2list = lookforNumbers(list_sink) + >>> for i in "3-(1.2)": + ... str2list.send(i) + >>> a = str2list.throw(STOOOP) + >>> print(a) + [3, '+', '-', '(', Decimal('1.2'), ')'] """ try: @@ -442,13 +471,21 @@ def lookforNumbers(target): except ValueError: if tok == '.': if "." in current: - raise ValueError(f"Can't build a number with 2 dots (current is {current})") + raise ParsingError(f"Can't build a number with 2 dots (current is {current})") elif len(current) == 0: - raise ValueError(f"Can't build a number starting with a dot") + raise ParsingError(f"Can't build a number starting with a dot") else: current += tok + elif tok == '-': + if len(current) > 0: + target_.send(typifiy_numbers(current)) + target_.send('+') + current = tok else: - if current: + if current == '-': + target_.send(current) + current = "" + elif current: target_.send(typifiy_numbers(current)) current = "" target_.send(tok) @@ -552,6 +589,22 @@ def str2(sink): >>> t = str2nestedlist(exp) >>> print(t) [2, '*', 'a', '*', [3, '+', 4]] + >>> exp = "-12(3-4)" + >>> t = str2nestedlist(exp) + >>> print(t) + [-12, '*', [3, '+', -4]] + >>> exp = "-a(3-4)" + >>> t = str2nestedlist(exp) + >>> print(t) + ['-', 'a', '*', [3, '+', -4]] + >>> exp = "3-a" + >>> t = str2nestedlist(exp) + >>> print(t) + [3, '+', '-', 'a'] + >>> exp = "1-(3+4)" + >>> t = str2nestedlist(exp) + >>> print(t) + [1, '+', '-', [3, '+', 4]] >>> from .tree import MutableTree >>> str2tree = str2(MutableTree.sink) @@ -587,6 +640,43 @@ def str2(sink): > + | > 3 | > 4 + >>> exp = "-12(3-4)" + >>> t = str2tree(exp) + >>> print(t) + * + > -12 + > + + | > 3 + | > -4 + >>> exp = "-a(3-4)" + >>> t = str2tree(exp) + >>> print(t) + - + > None + > * + | > a + | > + + | | > 3 + | | > -4 + >>> exp = "3-a" + >>> t = str2tree(exp) + >>> print(t) + + + > 3 + > - + | > None + | > a + >>> exp = "1-(3+4)" + >>> t = str2tree(exp) + >>> print(t) + + + > 1 + > - + | > None + | > + + | | > 3 + | | > 4 + """ lfop = lookfor(is_operator) operator_corout = partial(concurent_broadcast, lookfors = [lfop]) diff --git a/mapytex/calculus/core/tree.py b/mapytex/calculus/core/tree.py index a6cda98..63decb9 100644 --- a/mapytex/calculus/core/tree.py +++ b/mapytex/calculus/core/tree.py @@ -607,9 +607,7 @@ class MutableTree(Tree): * > 4 > + - | > - - | | > None - | | > 2 + | > -2 | > 3 """ str2mutTree = str2(cls.sink)