2016-02-23 10:53:13 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# encoding: utf-8
|
|
|
|
|
2016-03-06 15:18:01 +00:00
|
|
|
# from debug.tools import report
|
|
|
|
|
|
|
|
from ..generic import flatten_list
|
2016-02-23 10:53:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Operator():
|
|
|
|
|
|
|
|
"""The operator class, is a string (representation of the operator) with its arity"""
|
|
|
|
|
2016-03-06 15:18:01 +00:00
|
|
|
def __init__(self, operator="", name="", priority=0, actions=("", ""), txt="", tex="", arity=2, **kwrds):
|
2016-02-23 10:53:13 +00:00
|
|
|
""" Create an Operator """
|
|
|
|
self.operator = operator
|
|
|
|
self.name = name
|
|
|
|
self.arity = arity
|
|
|
|
self.priority = priority
|
|
|
|
self.actions = actions
|
|
|
|
self.txt = txt
|
|
|
|
self.tex = tex
|
|
|
|
|
|
|
|
self.isOperator = 1
|
|
|
|
|
|
|
|
def __call__(self, *args):
|
|
|
|
""" Calling this operator performs the rigth calculus """
|
|
|
|
if self.arity == 1:
|
|
|
|
return getattr(args[0], self.actions)()
|
|
|
|
|
|
|
|
elif self.arity == 2:
|
2016-03-06 15:18:01 +00:00
|
|
|
if issubclass(type(args[1]), int):
|
2016-02-23 10:53:13 +00:00
|
|
|
return getattr(args[0], self.actions[0])(args[1])
|
|
|
|
else:
|
|
|
|
return getattr(args[1], self.actions[1])(args[0])
|
|
|
|
|
|
|
|
def _render(self, link, *args):
|
|
|
|
"""Global step for __txt__ and __tex__
|
|
|
|
|
|
|
|
:param link: the link between operators
|
|
|
|
:param *args: the operands
|
|
|
|
:returns: the string with operator and operands
|
|
|
|
|
|
|
|
"""
|
|
|
|
if self.arity == 1:
|
|
|
|
op1 = self.l_parenthesis(args[0], True)
|
2016-03-06 15:18:01 +00:00
|
|
|
ans = link.format(op1=op1)
|
2016-02-23 10:53:13 +00:00
|
|
|
|
|
|
|
elif self.arity == 2:
|
|
|
|
op1 = self.l_parenthesis(args[0], True)
|
|
|
|
op2 = self.r_parenthesis(args[1], True)
|
2016-03-06 15:18:01 +00:00
|
|
|
ans = link.format(op1=op1, op2=op2)
|
2016-02-23 10:53:13 +00:00
|
|
|
|
|
|
|
ans = save_mainOp(ans, self)
|
|
|
|
return ans
|
|
|
|
|
|
|
|
def __repr__(self):
|
2016-02-27 06:07:54 +00:00
|
|
|
return str(self.operator)
|
2016-02-23 10:53:13 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return str(self.operator)
|
|
|
|
|
|
|
|
def __txt__(self, *args):
|
|
|
|
"""Txt rendering for the operator
|
|
|
|
|
|
|
|
:*args: Operands for this operation
|
|
|
|
:returns: String with operator and his operands
|
|
|
|
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> from .mul import Mul
|
|
|
|
>>> mul= Mul()
|
|
|
|
>>> from .add import Add
|
|
|
|
>>> add = Add()
|
|
|
|
>>> from .sub import Sub
|
|
|
|
>>> sub = Sub()
|
|
|
|
>>> from .sub1 import Sub1
|
|
|
|
>>> sub1 = Sub1()
|
|
|
|
>>> mul.__txt__('1','2')
|
2016-02-23 10:53:13 +00:00
|
|
|
'1 * 2'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> add.__txt__('1','2')
|
2016-02-23 10:53:13 +00:00
|
|
|
'1 + 2'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> f = save_mainOp('2 + 3',add)
|
|
|
|
>>> mul.__txt__(f, '4')
|
2016-02-23 10:53:13 +00:00
|
|
|
'( 2 + 3 ) * 4'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> f = save_mainOp('-3',sub1)
|
|
|
|
>>> sub1.__txt__(f)
|
2016-02-23 10:53:13 +00:00
|
|
|
'- ( -3 )'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> sub1.__txt__('-3')
|
2016-02-23 10:53:13 +00:00
|
|
|
'- ( -3 )'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> f = save_mainOp('2 + 3',add)
|
|
|
|
>>> sub1.__txt__(f)
|
2016-02-23 10:53:13 +00:00
|
|
|
'- ( 2 + 3 )'
|
|
|
|
"""
|
|
|
|
return self._render(self.txt, *args)
|
|
|
|
|
|
|
|
def __tex__(self, *args):
|
|
|
|
"""Tex rendering for the operator
|
|
|
|
|
|
|
|
:*args: Operands for this operation
|
|
|
|
:returns: String with operator and his operands
|
|
|
|
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> from .mul import Mul
|
|
|
|
>>> mul= Mul()
|
|
|
|
>>> from .add import Add
|
|
|
|
>>> add = Add()
|
|
|
|
>>> from .sub import Sub
|
|
|
|
>>> sub = Sub()
|
|
|
|
>>> from .sub1 import Sub1
|
|
|
|
>>> sub1 = Sub1()
|
|
|
|
>>> mul.__tex__('1','2')
|
2016-02-23 10:53:13 +00:00
|
|
|
'1 \\\\times 2'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> add.__tex__('1','2')
|
2016-02-23 10:53:13 +00:00
|
|
|
'1 + 2'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> f = save_mainOp('2 + 3',add)
|
|
|
|
>>> mul.__tex__(f, '4')
|
2016-02-23 10:53:13 +00:00
|
|
|
'( 2 + 3 ) \\\\times 4'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> f = save_mainOp('-3',sub1)
|
|
|
|
>>> sub1.__tex__(f)
|
2016-02-23 10:53:13 +00:00
|
|
|
'- ( -3 )'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> sub1.__tex__('-3')
|
2016-02-23 10:53:13 +00:00
|
|
|
'- ( -3 )'
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> f = save_mainOp('2 + 3',add)
|
|
|
|
>>> sub1.__tex__(f)
|
2016-02-23 10:53:13 +00:00
|
|
|
'- ( 2 + 3 )'
|
|
|
|
"""
|
|
|
|
return self._render(self.tex, *args)
|
|
|
|
|
|
|
|
def __p2i__(self, *args):
|
|
|
|
"""Fix list transformation for the operator
|
|
|
|
|
|
|
|
:*args: Operands for this operation
|
|
|
|
:returns: list with the operator surrounded by operands
|
|
|
|
|
2016-02-27 08:52:15 +00:00
|
|
|
>>> from .mul import Mul
|
|
|
|
>>> mul= Mul()
|
|
|
|
>>> from .add import Add
|
|
|
|
>>> add = Add()
|
|
|
|
>>> from .sub import Sub
|
|
|
|
>>> sub = Sub()
|
|
|
|
>>> from .sub1 import Sub1
|
|
|
|
>>> sub1 = Sub1()
|
|
|
|
>>> mul.__p2i__(1,2)
|
|
|
|
[1, *, 2]
|
|
|
|
>>> f = save_mainOp([2, add, 3],add)
|
|
|
|
>>> mul.__p2i__(f, 4)
|
|
|
|
['(', 2, +, 3, ')', *, 4]
|
|
|
|
>>> f = save_mainOp([sub1, 3],sub1)
|
|
|
|
>>> sub1.__p2i__(f)
|
|
|
|
[-, '(', -, 3, ')']
|
|
|
|
>>> sub1.__p2i__(-3)
|
|
|
|
[-, '(', -3, ')']
|
|
|
|
>>> f = save_mainOp([2, add, 3],add)
|
|
|
|
>>> sub1.__p2i__(f)
|
|
|
|
[-, '(', 2, +, 3, ')']
|
2016-02-23 10:53:13 +00:00
|
|
|
"""
|
|
|
|
if self.arity == 1:
|
|
|
|
op1 = self.l_parenthesis(args[0])
|
|
|
|
ans = flatten_list([self, op1])
|
|
|
|
|
|
|
|
elif self.arity == 2:
|
|
|
|
op1 = self.l_parenthesis(args[0])
|
|
|
|
op2 = self.r_parenthesis(args[1])
|
|
|
|
ans = flatten_list([op1, self, op2])
|
|
|
|
|
|
|
|
ans = save_mainOp(ans, self)
|
|
|
|
return ans
|
|
|
|
|
|
|
|
def l_parenthesis(self, opl, str_join=False):
|
|
|
|
""" Add parenthesis for left operand if necessary """
|
|
|
|
ans = opl
|
|
|
|
try:
|
|
|
|
# TODO: Je pige pas pourquoi quand on enlève .name ça marche plus... |lun. avril 27 19:07:24 CEST 2015
|
|
|
|
if opl.mainOp.name == "sub1":
|
|
|
|
ans = opl
|
|
|
|
elif opl.mainOp.priority < self.priority:
|
|
|
|
ans = flatten_list(["(", opl, ")"])
|
2016-03-06 15:18:01 +00:00
|
|
|
except AttributeError:
|
2016-02-23 10:53:13 +00:00
|
|
|
# op has not the attribute priority
|
|
|
|
pass
|
|
|
|
|
|
|
|
ans = flatten_list([ans])
|
|
|
|
if str_join:
|
|
|
|
ans = ' '.join([str(i) for i in ans])
|
|
|
|
return ans
|
|
|
|
|
|
|
|
def r_parenthesis(self, op, str_join=False):
|
|
|
|
""" Add parenthesis for rigth operand if necessary """
|
|
|
|
try:
|
|
|
|
if op.mainOp.priority < self.priority:
|
|
|
|
op = flatten_list(["(", op, ")"])
|
|
|
|
except AttributeError:
|
|
|
|
# op has not the attribute priority
|
|
|
|
try:
|
|
|
|
if int(op) < 0:
|
|
|
|
op = ['(', op, ')']
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
ans = flatten_list([op])
|
|
|
|
if str_join:
|
|
|
|
ans = ' '.join([str(i) for i in ans])
|
|
|
|
return ans
|
|
|
|
|
|
|
|
def uniq_desc(self):
|
|
|
|
""" Return the uniq description of the operator
|
|
|
|
:returns: (self.name, self.arity)
|
|
|
|
|
|
|
|
"""
|
|
|
|
return (self.operator, self.arity)
|
|
|
|
|
|
|
|
def __eq__(self, op2):
|
|
|
|
""" op1 == op2 """
|
2016-02-27 09:13:51 +00:00
|
|
|
try:
|
|
|
|
return self.name == op2.name and self.arity == op2.arity
|
|
|
|
except AttributeError:
|
|
|
|
return False
|
2016-02-23 10:53:13 +00:00
|
|
|
|
2016-03-06 15:18:01 +00:00
|
|
|
|
2016-02-23 10:53:13 +00:00
|
|
|
def save_mainOp(obj, mainOp):
|
|
|
|
"""Create a temporary class build over built-in type to stock the main operation of a calculus
|
|
|
|
|
|
|
|
:obj: the object to add the attribute
|
|
|
|
:mainOp: the main operator
|
|
|
|
:returns: the same object with the main operation attribute
|
|
|
|
"""
|
|
|
|
# TODO: À mettre avec render? |mar. févr. 23 09:45:22 EAT 2016
|
|
|
|
# TODO: On pourrait mettre un try avant de créer une nouvelle classe |mar. févr. 23 09:44:45 EAT 2016
|
|
|
|
Fake = type('fake_'+str(type(obj)), (type(obj),), {'mainOp': mainOp})
|
|
|
|
|
|
|
|
return Fake(obj)
|
|
|
|
|
|
|
|
|
|
|
|
# -----------------------------
|
|
|
|
# Reglages pour 'vim'
|
|
|
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
|
|
|
# cursor: 16 del
|