From a8a62864a6e81034ef4fe0ebfc213d0ca9047b4b Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Fri, 9 Mar 2018 19:31:46 +0300 Subject: [PATCH] Integrate MO inside str2 and in Tree (doctest are ok) --- mapytex/calculus/core/MO/__init__.py | 18 ++++ mapytex/calculus/core/MO/fraction.py | 82 +++++++++++++++ mapytex/calculus/core/MO/mo.py | 144 ++++++++++++++------------- mapytex/calculus/core/str2.py | 16 ++- mapytex/calculus/core/tree.py | 20 ++-- 5 files changed, 196 insertions(+), 84 deletions(-) create mode 100644 mapytex/calculus/core/MO/__init__.py create mode 100644 mapytex/calculus/core/MO/fraction.py diff --git a/mapytex/calculus/core/MO/__init__.py b/mapytex/calculus/core/MO/__init__.py new file mode 100644 index 0000000..b7851c5 --- /dev/null +++ b/mapytex/calculus/core/MO/__init__.py @@ -0,0 +1,18 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# +# Copyright © 2017 lafrite +# +# Distributed under terms of the MIT license. + +""" +MO: math objects +""" + +from .mo import * + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del diff --git a/mapytex/calculus/core/MO/fraction.py b/mapytex/calculus/core/MO/fraction.py new file mode 100644 index 0000000..36e2512 --- /dev/null +++ b/mapytex/calculus/core/MO/fraction.py @@ -0,0 +1,82 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# +# Copyright © 2017 lafrite +# +# Distributed under terms of the MIT license. + +from mapytex.calculus.core.tree import Tree +from .mo import MO, MOError + +__all__ = ["MOFraction"] + +class MOFraction(MO): + + """ Fraction math object""" + + def __init__(self, numerator, denominator, negative=False): + """ Initiate the MOFraction + + It can't be indempotent. + + :param numerator: Numerator of the Fraction + :param denominator: Denominator of the Fraction + :param negative: Is the fraction negative (not concidering sign of + numerator or denominator. + + >>> f = MOFraction(2, 3) + >>> f + + >>> f = MOFraction(2, 3, negative = True) + >>> f + + """ + value = Tree("/", + MO.factory(numerator), + MO.factory(denominator), + ) + MO.__init__(self, value) + + self._numerator = numerator + self._denominator = denominator + self.negative = negative + + @property + def __txt__(self): + # TODO: fonctionnement temporaire. Il faudrait utilser un moteur de rendu plus fin. |jeu. mars 8 15:26:49 EAT 2018 + try: + numerator = self._numerator.__txt__ + except AttributeError: + numerator = str(self._numerator) + + try: + denominator = self._denominator.__txt__ + except AttributeError: + denominator = str(self._denominator) + return "- "*self.negative + f"{numerator} / {denominator}" + + def __add__(self, other): + """ Overload * for MOFraction + + :param other: any other MO + :yields: calculus steps and the final yielded value is a MO. + + + >>> f = MOFraction(1, 2) + >>> g = MOFraction(3, 2) + """ + raise NotImplemented + + def __mul__(self, other): + raise NotImplemented + + def __truediv__(self, other): + raise NotImplemented + + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del diff --git a/mapytex/calculus/core/MO/mo.py b/mapytex/calculus/core/MO/mo.py index 90a001c..eca6891 100644 --- a/mapytex/calculus/core/MO/mo.py +++ b/mapytex/calculus/core/MO/mo.py @@ -6,11 +6,37 @@ # # Distributed under terms of the MIT license. -from mapytex.calculus.core.tree import Tree +from mapytex.calculus.core.coroutine import coroutine, STOOOP +from decimal import Decimal + +__all__ = ["moify", "MO", "MOstr"] class MOError(Exception): pass +@coroutine +def moify(target): + """ Coroutine which try to convert everything into an MO """ + try: + target_ = target() + except TypeError: + target_ = target + + try: + while True: + tok = yield + try: + target_.send(MOnumber(tok)) + except MOError: + try: + target_.send(MOstr(tok)) + except MOError: + target_.send(tok) + + except STOOOP as err: + yield target_.throw(err) + + class MO(object): """MO for math object @@ -117,6 +143,43 @@ class MO(object): """ return MO.factory(-self.value) + +class MOnumber(MO): + + """ Base number math object (int or Decimal) """ + + def __init__(self, value, negative=False): + """ Initiate a number MO + + >>> MOnumber(23) + + >>> MOnumber(-23) + + >>> MOnumber(23.3) + + >>> MOnumber(Decimal("23.3")) + + >>> a = MOnumber(23) + >>> MOnumber(a) + + >>> MOnumber("a") + Traceback (most recent call last): + ... + mapytex.calculus.core.MO.mo.MOError: The value of an MOnumber need to be a int, a float or a Decimal + + """ + try: + val = value.value + except AttributeError: + val = value + + if isinstance(val, int) or isinstance(val, Decimal): + MO.__init__(self, value) + elif isinstance(val, float): + MO.__init__(self, Decimal(val)) + else: + raise MOError("The value of an MOnumber need to be a int, a float or a Decimal") + class MOstr(MO): @@ -135,14 +198,18 @@ class MOstr(MO): >>> b + >>> a = MOstr("+") + Traceback (most recent call last): + ... + mapytex.calculus.core.MO.mo.MOError: An MOstr should be initiate with a alpha string, got + >>> MOstr("ui") Traceback (most recent call last): ... - mo.MOError: An MOstr should be initiate with a single caracter string + mapytex.calculus.core.MO.mo.MOError: An MOstr should be initiate with a single caracter string, got ui >>> MOstr(2) Traceback (most recent call last): ... - mo.MOError: An MOstr should be initiate with a string - the unknown + mapytex.calculus.core.MO.mo.MOError: An MOstr should be initiate with a string - the unknown, got 2 """ try: @@ -151,9 +218,11 @@ class MOstr(MO): val = value if not isinstance(val, str): - raise MOError("An MOstr should be initiate with a string - the unknown") + raise MOError(f"An MOstr should be initiate with a string - the unknown, got {val}") if len(val) != 1: - raise MOError("An MOstr should be initiate with a single caracter string") + raise MOError(f"An MOstr should be initiate with a single caracter string, got {val}") + if not val.isalpha(): + raise MOError(f"An MOstr should be initiate with a alpha string, got {val}") MO.__init__(self, value) self.negative = negative @@ -192,71 +261,6 @@ class MOstr(MO): def __neg__(self): return MO(self.value, not self.negative) -class MOFraction(MO): - - """ Fraction math object""" - - def __init__(self, numerator, denominator, negative=False): - """ Initiate the MOFraction - - It can't be indempotent. - - :param numerator: Numerator of the Fraction - :param denominator: Denominator of the Fraction - :param negative: Is the fraction negative (not concidering sign of - numerator or denominator. - - >>> f = MOFraction(2, 3) - >>> f - - >>> f = MOFraction(2, 3, negative = True) - >>> f - - """ - value = Tree("/", - MO.factory(numerator), - MO.factory(denominator), - ) - MO.__init__(self, value) - - self._numerator = numerator - self._denominator = denominator - self.negative = negative - - @property - def __txt__(self): - # TODO: fonctionnement temporaire. Il faudrait utilser un moteur de rendu plus fin. |jeu. mars 8 15:26:49 EAT 2018 - try: - numerator = self._numerator.__txt__ - except AttributeError: - numerator = str(self._numerator) - - try: - denominator = self._denominator.__txt__ - except AttributeError: - denominator = str(self._denominator) - return "- "*self.negative + f"{numerator} / {denominator}" - - def __add__(self, other): - """ Overload * for MOFraction - - :param other: any other MO - :yields: calculus steps and the final yielded value is a MO. - - - >>> f = MOFraction(1, 2) - >>> g = MOFraction(3, 2) - """ - raise NotImplemented - - def __mul__(self, other): - raise NotImplemented - - def __truediv__(self, other): - raise NotImplemented - - - # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/str2.py b/mapytex/calculus/core/str2.py index 3184d0e..704a822 100644 --- a/mapytex/calculus/core/str2.py +++ b/mapytex/calculus/core/str2.py @@ -14,6 +14,7 @@ from functools import partial from decimal import Decimal from .coroutine import * from .operator import is_operator +from .MO import moify __all__ = ["str2", ] @@ -563,7 +564,7 @@ def list_sink(): except STOOOP: yield ans -def str2(sink): +def str2(sink, convert_to_MO=True): """ Return a pipeline which parse an expression with the sink as an endpont :example: @@ -572,6 +573,11 @@ def str2(sink): >>> exp = "12+3*4" >>> t = str2nestedlist(exp) >>> print(t) + [, '+', , '*', ] + >>> str2nestedlist = str2(list_sink, False) + >>> exp = "12+3*4" + >>> t = str2nestedlist(exp) + >>> print(t) [12, '+', 3, '*', 4] >>> exp = "12*3+4" >>> t = str2nestedlist(exp) @@ -680,10 +686,12 @@ def str2(sink): """ lfop = lookfor(is_operator) operator_corout = partial(concurent_broadcast, lookfors = [lfop]) - def pipeline(expression): - str2_corout = lookforNumbers(operator_corout(missing_times(pparser(sink)))) - #str2_corout = lookforNumbers(operator_corout(pparser(sink))) + if convert_to_MO: + str2_corout = lookforNumbers(operator_corout(missing_times(moify(pparser(sink))))) + else: + str2_corout = lookforNumbers(operator_corout(missing_times(pparser(sink)))) + for i in expression: str2_corout.send(i) a = str2_corout.throw(STOOOP) diff --git a/mapytex/calculus/core/tree.py b/mapytex/calculus/core/tree.py index 63decb9..685f2dd 100644 --- a/mapytex/calculus/core/tree.py +++ b/mapytex/calculus/core/tree.py @@ -57,7 +57,7 @@ class Tree(object): self.right_value = right_value @classmethod - def from_str(cls, expression): + def from_str(cls, expression, convert_to_MO=True): """ Initiate a tree from an string expression :example: @@ -85,7 +85,7 @@ class Tree(object): | > n """ - t = MutableTree.from_str(expression) + t = MutableTree.from_str(expression, convert_to_MO) return cls.from_any_tree(t) @classmethod @@ -270,7 +270,7 @@ class Tree(object): :example: - >>> t = Tree.from_str("3*4+2") + >>> t = Tree.from_str("3*4+2", convert_to_MO=False) >>> print(t) + > * @@ -399,9 +399,9 @@ class Tree(object): >>> t = Tree.from_str("3+4+5*2") >>> [l for l in t.get_leafs()] - [3, 4, 5, 2] + [, , , ] >>> {type(l) for l in t.get_leafs()} - {} + {} """ try: yield from self.left_value.get_leafs(callback) @@ -584,7 +584,7 @@ class MutableTree(Tree): self.right_value = right_value @classmethod - def from_str(cls, expression): + def from_str(cls, expression, convert_to_MO=True): """ Initiate the MutableTree :example: @@ -610,7 +610,7 @@ class MutableTree(Tree): | > -2 | > 3 """ - str2mutTree = str2(cls.sink) + str2mutTree = str2(cls.sink, convert_to_MO) return str2mutTree(expression) @classmethod @@ -871,7 +871,7 @@ class AssocialTree(Tree): :example: - >>> t = Tree.from_str("3*4+2") + >>> t = Tree.from_str("3*4+2", convert_to_MO=False) >>> print(t) + > * @@ -921,7 +921,7 @@ class AssocialTree(Tree): ... return (op, (l, r)) >>> t = AssocialTree.from_str("3+4+5*2") >>> t.apply(to_nested) - ('+', (('+', (3, 4)), 'tree(*)')) + ('+', (('+', (, )), 'tree(*)')) """ try: @@ -954,7 +954,7 @@ class AssocialTree(Tree): >>> [l for l in t.get_leafs(str)] ['3', '4', '*\\n > 5\\n > 2'] >>> [ l for l in t.get_leafs(type) ] - [, , ] + [, , ] """ try: if self.left_value.node == self.node: