#!/usr/bin/env python # encoding: utf-8 # from debug.tools import report from ..generic import flatten_list class Operator(): """The operator class, is a string (representation of the operator) with its arity""" def __init__(self, operator="", name="", priority=0, actions=("", ""), txt="", tex="", arity=2, **kwrds): """ 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: if issubclass(type(args[1]), int): 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) ans = link.format(op1=op1) elif self.arity == 2: op1 = self.l_parenthesis(args[0], True) op2 = self.r_parenthesis(args[1], True) ans = link.format(op1=op1, op2=op2) ans = save_mainOp(ans, self) return ans def __repr__(self): return str(self.operator) 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 >>> 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') '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 )' """ 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 >>> 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') '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 )' """ 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 >>> 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, ')'] """ 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: if opl.mainOp.name == "sub1": ans = opl elif opl.mainOp.priority < self.priority: ans = flatten_list(["(", opl, ")"]) except AttributeError: # 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, opr, str_join=False): """ Add parenthesis for rigth operand if necessary """ ans = opr try: if opr.mainOp.priority < self.priority or \ (opr.mainOp.name == 'mul' and opr[0] == '-'): ans = flatten_list(["(", ans, ")"]) except AttributeError: # op has not the attribute priority try: if int(ans) < 0: ans = ['(', ans, ')'] except ValueError: pass ans = flatten_list([ans]) 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 """ try: return self.name == op2.name and self.arity == op2.arity except AttributeError: return False 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