diff --git a/mapytex/calculus/API/tokens/__init__.py b/mapytex/calculus/API/tokens/__init__.py index 7163976..ea66dc5 100644 --- a/mapytex/calculus/API/tokens/__init__.py +++ b/mapytex/calculus/API/tokens/__init__.py @@ -10,52 +10,84 @@ Tokens represents MathObject at API level """ -from ...core.MO import MO, MOnumber, MOstr +from ...core.MO import MO, MOnumber, MOstr, moify from ...core.MO.fraction import MOFraction from ...core.MO.monomial import MOstrPower, MOMonomial from ...core.MO.polynomial import MOpolynomial from decimal import Decimal as _Decimal +from .token import Token __all__ = ["factory"] +def tokenify(mo, name="", ancestor=None): + """ Transform a MO or a python builtin to the appropriate token -def factory(exp, name="", ancestor=None): - """ Transform a Expression with on MathObject (from core) to a appropriate token (from API) + :param mo: the thing to turn into a Token + :param name: a virtual name of the toke + :param ancestor: its ancestor :example: - >>> from ..expression import Expression - >>> a = Expression(MOnumber(2)) - >>> factory(a) + >>> a = MOnumber(2) + >>> tokenify(a) - >>> a = Expression(MOnumber(2.5)) - >>> factory(a) - - >>> a = Expression(MOFraction(2, 5)) - >>> factory(a) - - >>> a = Expression(MOstr('x')) - >>> factory(a) + >>> tokenify(2) + + >>> tokenify("x") - >>> a = Expression(MOstrPower('x', 2)) - >>> factory(a) + >>> tokenify(_Decimal("2.2")) + + >>> tokenify("2.2") + + >>> tokenify(2.2) + + + tokenify is idempotent on "mo" parameter + + >>> a = MOnumber(2) + >>> ta = tokenify(a) + >>> ta == tokenify(ta) + True + + """ + if isinstance(mo, MO): + return _tokenify(mo, name, ancestor) + elif isinstance(mo, Token): + return _tokenify(mo._mo, name, ancestor) + return _tokenify(moify(mo), name, ancestor) + + +def _tokenify(mo, name="", ancestor=None): + """ Transform a MO (from core) to the appropriate token (from API) + + :example: + >>> a = MOnumber(2) + >>> _tokenify(a) + + >>> a = MOnumber(2.5) + >>> _tokenify(a) + + >>> a = MOFraction(2, 5) + >>> _tokenify(a) + + >>> a = MOstr('x') + >>> _tokenify(a) + + >>> a = MOstrPower('x', 2) + >>> _tokenify(a) - >>> a = Expression(MOstrPower('x', 3)) - >>> factory(a) + >>> a = MOstrPower('x', 3) + >>> _tokenify(a) - >>> a = Expression(MOMonomial(3, 'x', 1)) - >>> factory(a) + >>> a = MOMonomial(3, 'x', 1) + >>> _tokenify(a) - >>> a = Expression(MOMonomial(3, 'x', 2)) - >>> factory(a) + >>> a = MOMonomial(3, 'x', 2) + >>> _tokenify(a) - >>> a = Expression(MOMonomial(3, 'x', 3)) - >>> factory(a) + >>> a = MOMonomial(3, 'x', 3) + >>> _tokenify(a) """ - mo = exp._tree - if not isinstance(mo, MO): - raise TypeError(f"Can't build Token from not computed Expression (got {mo})") - if isinstance(mo, MOnumber): if isinstance(mo.value, int): from .number import Integer @@ -104,6 +136,47 @@ def factory(exp, name="", ancestor=None): raise TypeError(f"{type(mo)} is unknown MathObject") + +def factory(exp, name="", ancestor=None): + """ Transform a Expression with on single MathObject (from core) to a appropriate token (from API) + + :example: + >>> from ..expression import Expression + >>> a = Expression(MOnumber(2)) + >>> factory(a) + + >>> a = Expression(MOnumber(2.5)) + >>> factory(a) + + >>> a = Expression(MOFraction(2, 5)) + >>> factory(a) + + >>> a = Expression(MOstr('x')) + >>> factory(a) + + >>> a = Expression(MOstrPower('x', 2)) + >>> factory(a) + + >>> a = Expression(MOstrPower('x', 3)) + >>> factory(a) + + >>> a = Expression(MOMonomial(3, 'x', 1)) + >>> factory(a) + + >>> a = Expression(MOMonomial(3, 'x', 2)) + >>> factory(a) + + >>> a = Expression(MOMonomial(3, 'x', 3)) + >>> factory(a) + + """ + mo = exp._tree + if not isinstance(mo, MO): + raise TypeError(f"Can't build Token from not computed Expression (got {mo})") + + return _tokenify(mo, name, ancestor) + + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/MO/atoms.py b/mapytex/calculus/core/MO/atoms.py index 6f5eba8..f9b505d 100644 --- a/mapytex/calculus/core/MO/atoms.py +++ b/mapytex/calculus/core/MO/atoms.py @@ -91,6 +91,12 @@ class MOnumber(Atom): >>> MOnumber(Decimal("-23.3")) + Or directly passe a decimal string + >>> MOnumber("23.3") + + >>> MOnumber("-23.3") + + MOnumber initialisation is idempotent >>> a = MOnumber(23) @@ -100,7 +106,7 @@ class MOnumber(Atom): >>> MOnumber("a") Traceback (most recent call last): ... - mapytex.calculus.core.MO.exceptions.MOError: ('The value of an MOnumber need to be a int, a float or a Decimal', "(got )") + mapytex.calculus.core.MO.exceptions.MOError: ('The value of an MOnumber need to be a int, a float, a Decimal or a decimal string', "(got )") Atoms specific property and methods @@ -122,10 +128,15 @@ class MOnumber(Atom): elif isinstance(value, float): Atom.__init__(self, Decimal(value)) else: - raise MOError( - "The value of an MOnumber need to be a int, a float or a Decimal", - f"(got {type(value)})", - ) + try: + float(value) + except (ValueError, TypeError): + raise MOError( + "The value of an MOnumber need to be a int, a float, a Decimal or a decimal string", + f"(got {type(value)})", + ) + else: + Atom.__init__(self, Decimal(value)) self._signature = "scalar"