2018-12-07 09:27:50 +00:00
|
|
|
#! /usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# vim:fenc=utf-8
|
|
|
|
#
|
|
|
|
# Copyright © 2017 lafrite <lafrite@Poivre>
|
|
|
|
#
|
|
|
|
# Distributed under terms of the MIT license.
|
|
|
|
|
|
|
|
"""
|
|
|
|
Tokens represents MathObject at API level
|
|
|
|
|
|
|
|
"""
|
2019-07-17 07:25:12 +00:00
|
|
|
from ...core.MO import MO, MOnumber, MOstr, moify
|
2018-12-07 09:27:50 +00:00
|
|
|
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
|
2019-07-17 07:49:50 +00:00
|
|
|
from functools import wraps
|
2019-07-17 07:25:12 +00:00
|
|
|
from .token import Token
|
2018-12-07 09:27:50 +00:00
|
|
|
|
|
|
|
__all__ = ["factory"]
|
|
|
|
|
2019-07-17 07:49:50 +00:00
|
|
|
|
2019-07-17 07:25:12 +00:00
|
|
|
def tokenify(mo, name="", ancestor=None):
|
|
|
|
""" Transform a MO or a python builtin to the appropriate token
|
2019-05-14 04:55:56 +00:00
|
|
|
|
2019-07-17 07:25:12 +00:00
|
|
|
:param mo: the thing to turn into a Token
|
|
|
|
:param name: a virtual name of the toke
|
|
|
|
:param ancestor: its ancestor
|
2018-12-07 10:23:05 +00:00
|
|
|
|
|
|
|
:example:
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> a = MOnumber(2)
|
|
|
|
>>> tokenify(a)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Integer 2>
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> tokenify(2)
|
|
|
|
<Integer 2>
|
|
|
|
>>> tokenify("x")
|
|
|
|
<Linear x>
|
|
|
|
>>> 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)
|
2019-07-17 07:49:50 +00:00
|
|
|
|
|
|
|
if isinstance(mo, Token):
|
|
|
|
if name == "":
|
|
|
|
_name = mo.name
|
|
|
|
else:
|
|
|
|
_name = name
|
|
|
|
if ancestor is None:
|
|
|
|
_ancestor = mo._ancestor
|
|
|
|
else:
|
|
|
|
_ancestor = ancestor
|
|
|
|
return _tokenify(mo._mo, _name, _ancestor)
|
|
|
|
|
2019-07-17 07:25:12 +00:00
|
|
|
return _tokenify(moify(mo), name, ancestor)
|
|
|
|
|
|
|
|
|
2019-07-17 07:49:50 +00:00
|
|
|
def to_be_token(func):
|
|
|
|
""" Decorator to ensure that the return value is a Token """
|
|
|
|
@wraps(func)
|
|
|
|
def wrapped(*args, **kwds):
|
|
|
|
ans = func(*args, **kwds)
|
|
|
|
try:
|
|
|
|
return [tokenify(t) for t in ans]
|
|
|
|
except TypeError:
|
|
|
|
return tokenify(ans)
|
|
|
|
return wrapped
|
|
|
|
|
|
|
|
|
2019-07-17 07:25:12 +00:00
|
|
|
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)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Decimal 2.5>
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> a = MOFraction(2, 5)
|
|
|
|
>>> _tokenify(a)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Fraction 2 / 5>
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> a = MOstr('x')
|
|
|
|
>>> _tokenify(a)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Linear x>
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> a = MOstrPower('x', 2)
|
|
|
|
>>> _tokenify(a)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Quadratic x^2>
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> a = MOstrPower('x', 3)
|
|
|
|
>>> _tokenify(a)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Polynomial x^3>
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> a = MOMonomial(3, 'x', 1)
|
|
|
|
>>> _tokenify(a)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Linear 3x>
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> a = MOMonomial(3, 'x', 2)
|
|
|
|
>>> _tokenify(a)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Quadratic 3x^2>
|
2019-07-17 07:25:12 +00:00
|
|
|
>>> a = MOMonomial(3, 'x', 3)
|
|
|
|
>>> _tokenify(a)
|
2018-12-07 10:23:05 +00:00
|
|
|
<Polynomial 3x^3>
|
2018-12-07 09:27:50 +00:00
|
|
|
"""
|
|
|
|
if isinstance(mo, MOnumber):
|
|
|
|
if isinstance(mo.value, int):
|
2019-07-15 09:09:59 +00:00
|
|
|
from .number import Integer
|
2019-07-17 07:49:50 +00:00
|
|
|
|
2018-12-13 09:44:52 +00:00
|
|
|
return Integer.from_mo(mo, name, ancestor)
|
2018-12-07 09:27:50 +00:00
|
|
|
elif isinstance(mo.value, _Decimal):
|
2019-07-15 09:09:59 +00:00
|
|
|
from .number import Decimal
|
2019-07-17 07:49:50 +00:00
|
|
|
|
2018-12-13 09:44:52 +00:00
|
|
|
return Decimal.from_mo(mo, name, ancestor)
|
2018-12-07 10:23:05 +00:00
|
|
|
|
|
|
|
raise TypeError(f"Can't build from MOnumber ({mo}) neither int nor decimal")
|
2018-12-07 09:27:50 +00:00
|
|
|
|
2019-07-17 07:49:50 +00:00
|
|
|
if isinstance(mo, MOFraction):
|
2019-05-14 04:55:56 +00:00
|
|
|
if isinstance(mo._denominator, MOnumber) and isinstance(
|
|
|
|
mo._numerator, MOnumber
|
|
|
|
):
|
2019-07-15 09:09:59 +00:00
|
|
|
from .number import Fraction
|
2019-07-17 07:49:50 +00:00
|
|
|
|
2018-12-13 09:44:52 +00:00
|
|
|
return Fraction.from_mo(mo, name, ancestor)
|
2018-12-07 10:23:05 +00:00
|
|
|
|
2019-05-14 04:55:56 +00:00
|
|
|
raise TypeError(
|
|
|
|
f"Can't build from MOFraction ({mo}) numerator and denominator are not MOnumber"
|
|
|
|
)
|
2018-12-07 09:27:50 +00:00
|
|
|
|
2019-07-17 07:49:50 +00:00
|
|
|
if isinstance(mo, (MOstr, MOstrPower, MOMonomial, MOpolynomial)):
|
2018-12-07 10:23:05 +00:00
|
|
|
if not isinstance(mo._variable, (MOstr, str)):
|
2019-05-14 04:55:56 +00:00
|
|
|
raise TypeError(
|
|
|
|
f"Can't build Polynom over something else than a letter (got {mo._variable})"
|
|
|
|
)
|
|
|
|
if (
|
|
|
|
isinstance(mo, MOstr)
|
|
|
|
or (isinstance(mo, MOMonomial) and mo.power.value == 1)
|
|
|
|
or (isinstance(mo, MOpolynomial) and mo.power.value == 1)
|
|
|
|
):
|
2019-07-15 09:09:59 +00:00
|
|
|
from .polynomial import Linear
|
2019-07-17 07:49:50 +00:00
|
|
|
|
2018-12-13 09:44:52 +00:00
|
|
|
return Linear.from_mo(mo, name, ancestor)
|
2019-05-14 04:55:56 +00:00
|
|
|
elif (
|
|
|
|
(isinstance(mo, MOstrPower) and mo.power.value == 2)
|
|
|
|
or (isinstance(mo, MOMonomial) and mo.power.value == 2)
|
|
|
|
or (isinstance(mo, MOpolynomial) and mo.power.value == 2)
|
|
|
|
):
|
2019-07-15 09:09:59 +00:00
|
|
|
from .polynomial import Quadratic
|
2019-07-17 07:49:50 +00:00
|
|
|
|
2018-12-13 09:44:52 +00:00
|
|
|
return Quadratic.from_mo(mo, name, ancestor)
|
2018-12-07 10:23:05 +00:00
|
|
|
else:
|
2019-07-15 09:09:59 +00:00
|
|
|
from .polynomial import Polynomial
|
2018-12-07 10:23:05 +00:00
|
|
|
|
2019-07-17 07:49:50 +00:00
|
|
|
return Polynomial.from_mo(mo, name, ancestor)
|
2018-12-07 09:27:50 +00:00
|
|
|
|
2019-07-17 07:49:50 +00:00
|
|
|
raise TypeError(f"{type(mo)} is unknown MathObject")
|
2019-05-14 04:55:56 +00:00
|
|
|
|
2019-07-17 07:25:12 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
2018-12-07 09:27:50 +00:00
|
|
|
# -----------------------------
|
|
|
|
# Reglages pour 'vim'
|
|
|
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
|
|
# cursor: 16 del
|