Feat: tokenify for everything!

This commit is contained in:
Bertrand Benjamin 2019-07-17 09:25:12 +02:00
parent a32b684b6b
commit d75fd4c4cf
2 changed files with 117 additions and 33 deletions

View File

@ -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)
<Integer 2>
>>> a = Expression(MOnumber(2.5))
>>> factory(a)
<Decimal 2.5>
>>> a = Expression(MOFraction(2, 5))
>>> factory(a)
<Fraction 2 / 5>
>>> a = Expression(MOstr('x'))
>>> factory(a)
>>> tokenify(2)
<Integer 2>
>>> tokenify("x")
<Linear x>
>>> a = Expression(MOstrPower('x', 2))
>>> factory(a)
>>> tokenify(_Decimal("2.2"))
<Decimal 2.2>
>>> tokenify("2.2")
<Decimal 2.2>
>>> tokenify(2.2)
<Decimal 2.20000000000000017763568394002504646778106689453125>
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)
<Integer 2>
>>> a = MOnumber(2.5)
>>> _tokenify(a)
<Decimal 2.5>
>>> a = MOFraction(2, 5)
>>> _tokenify(a)
<Fraction 2 / 5>
>>> a = MOstr('x')
>>> _tokenify(a)
<Linear x>
>>> a = MOstrPower('x', 2)
>>> _tokenify(a)
<Quadratic x^2>
>>> a = Expression(MOstrPower('x', 3))
>>> factory(a)
>>> a = MOstrPower('x', 3)
>>> _tokenify(a)
<Polynomial x^3>
>>> a = Expression(MOMonomial(3, 'x', 1))
>>> factory(a)
>>> a = MOMonomial(3, 'x', 1)
>>> _tokenify(a)
<Linear 3x>
>>> a = Expression(MOMonomial(3, 'x', 2))
>>> factory(a)
>>> a = MOMonomial(3, 'x', 2)
>>> _tokenify(a)
<Quadratic 3x^2>
>>> a = Expression(MOMonomial(3, 'x', 3))
>>> factory(a)
>>> a = MOMonomial(3, 'x', 3)
>>> _tokenify(a)
<Polynomial 3x^3>
"""
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)
<Integer 2>
>>> a = Expression(MOnumber(2.5))
>>> factory(a)
<Decimal 2.5>
>>> a = Expression(MOFraction(2, 5))
>>> factory(a)
<Fraction 2 / 5>
>>> a = Expression(MOstr('x'))
>>> factory(a)
<Linear x>
>>> a = Expression(MOstrPower('x', 2))
>>> factory(a)
<Quadratic x^2>
>>> a = Expression(MOstrPower('x', 3))
>>> factory(a)
<Polynomial x^3>
>>> a = Expression(MOMonomial(3, 'x', 1))
>>> factory(a)
<Linear 3x>
>>> a = Expression(MOMonomial(3, 'x', 2))
>>> factory(a)
<Quadratic 3x^2>
>>> a = Expression(MOMonomial(3, 'x', 3))
>>> factory(a)
<Polynomial 3x^3>
"""
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:

View File

@ -91,6 +91,12 @@ class MOnumber(Atom):
>>> MOnumber(Decimal("-23.3"))
<MOnumber - 23.3>
Or directly passe a decimal string
>>> MOnumber("23.3")
<MOnumber 23.3>
>>> 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 <class 'str'>)")
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 <class 'str'>)")
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"