From 6e99dadd395dc3f783bdfa7799f47584e17f8bb0 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sun, 2 Nov 2014 08:19:31 +0100 Subject: [PATCH] Create real class Operator and include it into expression (need to fix render now) --- pymath/expression.py | 67 ++++++++++++++++++++------------------------ pymath/generic.py | 11 -------- pymath/operator.py | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 48 deletions(-) create mode 100644 pymath/operator.py diff --git a/pymath/expression.py b/pymath/expression.py index ca1fae4..e24359c 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -1,7 +1,8 @@ #!/usr/bin/env python # encoding: utf-8 -from .generic import Stack, flatten_list, expand_list, Operator +from .generic import Stack, flatten_list, expand_list +from .operator import Operator from .fraction import Fraction from .renders import txt, post2in_fix, tex @@ -81,20 +82,36 @@ class Expression(object): tmpTokenList = [] while len(tokenList) > 2: - # on va chercher les motifs du genre A B + pour les calculer - if self.isNumber(tokenList[0]) and self.isNumber(tokenList[1]) and self.isOperator(tokenList[2]): + # on va chercher les motifs du genre A B +, quad l'operateur est d'arité 2, pour les calculer + if self.isNumber(tokenList[0]) and self.isNumber(tokenList[1]) \ + and type(tokenList[2]) == Operator and tokenList[2].arity == 2 : # S'il y a une opération à faire op1 = tokenList[0] op2 = tokenList[1] - token = tokenList[2] + operator = tokenList[2] - res = self.doMath(token, op1, op2) + res = operator(op1, op2) tmpTokenList.append(res) # Comme on vient de faire le calcul, on peut détruire aussi les deux prochains termes del tokenList[0:3] + + elif self.isNumber(tokenList[0]) \ + and type(tokenList[1]) == Operator and tokenList[1].arity == 1 : + + # S'il y a une opération à faire + op1 = tokenList[0] + operator = tokenList[1] + + res = operator(op1) + + tmpTokenList.append(res) + + # Comme on vient de faire le calcul, on peut détruire aussi les deux prochains termes + del tokenList[0:2] + else: tmpTokenList.append(tokenList[0]) @@ -106,7 +123,9 @@ class Expression(object): if len(steps[:-1]) > 0: self.steps += [flatten_list(s) for s in steps[:-1]] + print("self.steps -> ", self.steps) self.child = Expression(steps[-1]) + print("self.child -> ", self.child) ## --------------------- ## String parsing @@ -281,7 +300,6 @@ class Expression(object): arity_Stack.push(arity + 1) elif cls.isOperator(token): - # On doit ajouter la condition == str sinon python ne veut pas tester l'appartenance à la chaine de caractère. while (not opStack.isEmpty()) and (cls.PRIORITY[opStack.peek()] >= cls.PRIORITY[token]): op = opStack.pop() postfix_tokens.append(op) @@ -308,32 +326,6 @@ class Expression(object): return postfix_tokens - ## --------------------- - ## Computing the expression - - @staticmethod - def doMath(op, op1, op2): - """Compute "op1 op op2" or create a fraction - - :param op: operator - :param op1: first operande - :param op2: second operande - :returns: string representing the result - - """ - if op == "/": - ans = [Fraction(op1, op2)] - ans += ans[0].simplify() - return ans - else: - if type(op2) != int: - operations = {"+": "__radd__", "-": "__rsub__", "*": "__rmul__"} - return getattr(op2,operations[op])(op1) - else: - operations = {"+": "__add__", "-": "__sub__", "*": "__mul__", "^": "__pow__"} - return getattr(op1,operations[op])(op2) - - ## --------------------- ## Recognize numbers and operators @@ -367,12 +359,13 @@ def test(exp): print("\n") if __name__ == '__main__': - Expression.STR_RENDER = txt - #exp = "2 ^ 3 * 5" - #test(exp) + #Expression.STR_RENDER = txt + Expression.STR_RENDER = lambda x: str(x) + exp = "2 ^ 3 * 5" + test(exp) - #exp = "1 + 3 * 5" - #test(exp) + exp = "1 + 3 * 5" + test(exp) #exp = "2 * 3 * 3 * 5" #test(exp) diff --git a/pymath/generic.py b/pymath/generic.py index f5ee9ba..959c66a 100644 --- a/pymath/generic.py +++ b/pymath/generic.py @@ -57,17 +57,6 @@ class Stack(object): def __add__(self, addList): return self.items + addList -class Operator(str): - - """The operator class, is a string (representation of the operator) with its arity (?!? - arrite)""" - - def __new__(cls, operator, arity = 2): - op = str.__new__(cls, operator) - op.arity = arity - return op - - - def flatten_list(a, result=None): """Flattens a nested list. diff --git a/pymath/operator.py b/pymath/operator.py new file mode 100644 index 0000000..138ea65 --- /dev/null +++ b/pymath/operator.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +class Operator(str): + + """The operator class, is a string (representation of the operator) with its arity""" + + OPERATORS = { \ + "+": ["", "", ("__add__","__radd__")],\ + "-": ["", "__neg__", ("__sub__", "__rsub__")], \ + "*": ["", "", ("__mul__", "__rmul__")], \ + "/": ["", "", ("__div__","__rdiv__")], \ + "^": ["", "", ("__pow__", "")] \ + } + + def __new__(cls, operator, arity = 2): + op = str.__new__(cls, operator) + op.arity = arity + + op.actions = cls.OPERATORS[operator][arity] + + return op + + 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: + # C'est moche mais je veux que ça marche... + if str(self) == "/": + ans = [Fraction(op1, op2)] + ans += ans[0].simplify() + return ans + else: + if type(args[1]) == int: + return getattr(args[0], self.actions[0])(args[1]) + else: + return getattr(args[1], self.actions[1])(args[0]) + + + + + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del