diff --git a/pymbolic/mapper/stringifier.py b/pymbolic/mapper/stringifier.py index ce6f0b8eacbc55b06ac77d5e43b6f3cedf2b9cc7..43e63f93bbdf142438d9a9c9ae0d754f82d7b9d1 100644 --- a/pymbolic/mapper/stringifier.py +++ b/pymbolic/mapper/stringifier.py @@ -184,36 +184,39 @@ class StringifyMapper(pymbolic.mapper.Mapper): enclosing_prec, PREC_SUM) def map_product(self, expr, enclosing_prec, *args, **kwargs): + # Spaces prevent '**z' (times dereference z), which + # is hard to read. + # Use PREC_SUM to enforce correct order of operations + # in a series of products, quotients, and remainders. + # Without it the mapper leaves out parentheses + # and the series evaluates left to right. return self.parenthesize_if_needed( self.join_rec("*", expr.children, PREC_PRODUCT, *args, **kwargs), - enclosing_prec, PREC_PRODUCT) + enclosing_prec, PREC_SUM) def map_quotient(self, expr, enclosing_prec, *args, **kwargs): + # (-1) * ((-1)*x / 5) should not reassociate. Therefore raise precedence + # on the numerator and shield against surrounding products. return self.parenthesize_if_needed( - self.format("%s / %s", - # space is necessary--otherwise '/*' becomes - # start-of-comment in C. ('*' from dereference) - self.rec(expr.numerator, PREC_PRODUCT, *args, **kwargs), - self.rec( - expr.denominator, PREC_POWER, # analogous to ^{-1} - *args, **kwargs)), - enclosing_prec, PREC_PRODUCT) + self.format("%s / %s", + # space is necessary--otherwise '/*' becomes + # start-of-comment in C. ('*' from dereference) + self.rec(expr.numerator, PREC_PRODUCT, *args, **kwargs), + self.rec( + expr.denominator, PREC_POWER, # analogous to ^{-1} + *args, **kwargs)), + enclosing_prec, PREC_SUM) def map_floor_div(self, expr, enclosing_prec, *args, **kwargs): # (-1) * ((-1)*x // 5) should not reassociate. Therefore raise precedence # on the numerator and shield against surrounding products. - - result = self.format("%s // %s", - self.rec(expr.numerator, PREC_POWER, *args, **kwargs), - self.rec( - expr.denominator, PREC_POWER, # analogous to ^{-1} - *args, **kwargs)) - - # Note ">=", not ">" as in parenthesize_if_needed(). - if enclosing_prec >= PREC_PRODUCT: - return "(%s)" % result - else: - return result + return self.parenthesize_if_needed( + self.format("%s // %s", + self.rec(expr.numerator, PREC_PRODUCT, *args, **kwargs), + self.rec( + expr.denominator, PREC_POWER, # analogous to ^{-1} + *args, **kwargs)), + enclosing_prec, PREC_SUM) def map_power(self, expr, enclosing_prec, *args, **kwargs): return self.parenthesize_if_needed( @@ -223,11 +226,15 @@ class StringifyMapper(pymbolic.mapper.Mapper): enclosing_prec, PREC_POWER) def map_remainder(self, expr, enclosing_prec, *args, **kwargs): - return self.format("(%s %% %s)", - self.rec(expr.numerator, PREC_PRODUCT, *args, **kwargs), - self.rec( - expr.denominator, PREC_POWER, # analogous to ^{-1} - *args, **kwargs)) + # (-1) * ((-1)*x % 5) should not reassociate. Therefore raise precedence + # on the numerator and shield against surrounding products. + return self.parenthesize_if_needed( + self.format("%s %% %s", + self.rec(expr.numerator, PREC_PRODUCT, *args, **kwargs), + self.rec( + expr.denominator, PREC_POWER, # analogous to ^{-1} + *args, **kwargs)), + enclosing_prec, PREC_SUM) def map_polynomial(self, expr, enclosing_prec, *args, **kwargs): from pymbolic.primitives import flattened_sum