From 3d7018c2c7e0b8a3185b5ae90c6a3a3ba4e8bb5b Mon Sep 17 00:00:00 2001 From: lafrite Date: Sun, 9 Nov 2014 10:35:49 +0100 Subject: [PATCH] Operator knows how to be printed --- pymath/operator.py | 177 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 169 insertions(+), 8 deletions(-) diff --git a/pymath/operator.py b/pymath/operator.py index 46bc53e..72c5061 100644 --- a/pymath/operator.py +++ b/pymath/operator.py @@ -3,19 +3,35 @@ from .fraction import Fraction +from .generic import flatten_list class Operator(str): """The operator class, is a string (representation of the operator) with its arity""" - PRIORITY = {"^": 5, "/": 4, "*" : 3, ":": 3, "+": 2, "-":2, "(": 1} + PRIORITY = {"^": [0, 5], "/": [0, 4], "*" : [0,3], ":": [0,3], "+": [0,1], "-":[2,1]} OPERATIONS = { \ - "+": ["", "", ("__add__","__radd__")],\ - "-": ["", "__neg__", ("__sub__", "__rsub__")], \ - "*": ["", "", ("__mul__", "__rmul__")], \ - "/": ["", "", ("__div__","__rdiv__")], \ - "^": ["", "", ("__pow__", "")] \ + "+": ["", ("__add__","__radd__")],\ + "-": ["__neg__", ("__sub__", "__rsub__")], \ + "*": ["", ("__mul__", "__rmul__")], \ + "/": ["", ("__div__","__rdiv__")], \ + "^": ["", ("__pow__", "")] \ } + TXT = { \ + "+": ["", "{op1} + {op2}"] ,\ + "-": ["- {op1}", "{op1} - {op2}"] ,\ + "*": ["", "{op1} * {op2}"] ,\ + "/": ["", "{op1} / {op2}"] ,\ + "^": ["", "{op1} ^ {op2}"] ,\ + } + TEX = { \ + "+": ["", "{op1} + {op2}"] ,\ + "-": ["- {op1}", "{op1} - {op2}"] ,\ + "*": ["", "{op1} \\times {op2}"] ,\ + "/": ["", "\\frac{{ {op1} }}{{ {op2} }}"] ,\ + "^": ["", "{op1}^{{ {op2} }}"] ,\ + } + def __new__(cls, operator, arity = 2): op = str.__new__(cls, operator) @@ -23,8 +39,10 @@ class Operator(str): # TODO: Add op.visibility |sam. nov. 8 17:00:08 CET 2014 - op.priority = cls.PRIORITY[operator] - op.actions = cls.OPERATIONS[operator][arity] + op.priority = cls.PRIORITY[operator][arity - 1] + op.actions = cls.OPERATIONS[operator][arity-1] + op._txt = cls.TXT[operator][arity-1] + op._tex = cls.TEX[operator][arity-1] op.isOperator = 1 @@ -47,6 +65,149 @@ class Operator(str): else: return getattr(args[1], self.actions[1])(args[0]) + def __txt__(self, *args): + """Txt rendering for the operator + + :*args: Operands for this operation + :returns: String with operator and his operands + + >>> mul = Operator("*", 2) + >>> add = Operator("+", 2) + >>> sub1 = Operator("-", 1) + >>> div = Operator("/", 1) + >>> mul.__txt__(1,2) + '1 * 2' + >>> add.__txt__(1,2) + '1 + 2' + >>> f = save_mainOp('2 + 3',add) + >>> mul.__txt__(f, 4) + '( 2 + 3 ) * 4' + >>> f = save_mainOp('-3',sub1) + >>> sub1.__txt__(f) + '- ( -3 )' + >>> sub1.__txt__(-3) + '- ( -3 )' + >>> f = save_mainOp('2 + 3',add) + >>> sub1.__txt__(f) + '- ( 2 + 3 )' + """ + + #vive le inline? ... + replacement = {"op"+str(i+1): ' '.join([str(o) if type(o)==int else o for o in self.add_parenthesis(op)]) for (i,op) in enumerate(args)} + + return self._txt.format(**replacement) + + def __tex__(self, *args): + """Tex rendering for the operator + + :*args: Operands for this operation + :returns: String with operator and his operands + + >>> mul = Operator("*", 2) + >>> add = Operator("+", 2) + >>> sub1 = Operator("-", 1) + >>> div = Operator("/", 1) + >>> mul.__tex__(1,2) + '1 \\\\times 2' + >>> add.__tex__(1,2) + '1 + 2' + >>> f = save_mainOp('2 + 3',add) + >>> mul.__tex__(f, 4) + '( 2 + 3 ) \\\\times 4' + >>> f = save_mainOp('-3',sub1) + >>> sub1.__tex__(f) + '- ( -3 )' + >>> sub1.__tex__(-3) + '- ( -3 )' + >>> f = save_mainOp('2 + 3',add) + >>> sub1.__tex__(f) + '- ( 2 + 3 )' + """ + replacement = {"op"+str(i+1): ' '.join([str(o) if type(o)==int else o for o in self.add_parenthesis(op)]) for (i,op) in enumerate(args)} + return self._tex.format(**replacement) + + def __p2i__(self, *args): + """Fix list transformation for the operator + + :*args: Operands for this operation + :returns: list with the operator surrounded by operands + + >>> mul = Operator("*", 2) + >>> add = Operator("+", 2) + >>> sub1 = Operator("-", 1) + >>> 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, ')'] + """ + # TODO: Attention à gestion des fractions qui se comportent chelou avec les parenthèses |dim. nov. 9 09:21:52 CET 2014 + if self.arity == 1: + # TODO: Marche juste avec -, il faudra voir quand il y aura d'autres operateurs unitaires |dim. nov. 9 09:24:53 CET 2014 + op1 = self.add_parenthesis(args[0]) + return flatten_list([self, op1]) + + elif self.arity == 2: + op1 = self.add_parenthesis(args[0]) + op2 = self.add_parenthesis(args[1]) + return flatten_list([op1, self, op2]) + + def add_parenthesis(self, op): + """ Add parenthesis if necessary """ + try: + if op.mainOp.priority < self.priority: + op = flatten_list(["("] + [op] + [")"]) + except AttributeError: + if type(op) == int and op < 0: + op = ['(', op, ')'] + return flatten_list([op]) + + + + +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 + """ + class Fake(type(obj)): + """ The fake class """ + def __new__(cls, obj): + op = type(obj).__new__(cls, obj) + op.mainOp = mainOp + return op + + return Fake(obj) + +if __name__ == '__main__': + #op = Operator("+", 2) + #print(op.__txt__(1,2)) + #mul = Operator("*", 2) + #add = Operator("+", 2) + #sub1 = Operator("-", 1) + #div = Operator("/", 1) + #print(mul.__txt__(1,2)) + #print(add.__txt__(1,2)) + #f = save_mainOp('2 + 3',add) + #print(mul.__txt__(f, 4)) + #f = save_mainOp('-3',sub1) + #print(sub1.__txt__(f)) + #print(sub1.__txt__(-3)) + #f = save_mainOp('2 + 3',add) + #print(sub1.__txt__(f)) + + import doctest + doctest.testmod()