diff --git a/doc/primitives.rst b/doc/primitives.rst index 8d03ac1f7ac7a6ac0931bbdaa4c296bc7f4ebb33..7442cd11265e9d005006467622068cf2fc0c9f42 100644 --- a/doc/primitives.rst +++ b/doc/primitives.rst @@ -65,6 +65,36 @@ Sums, products and such :undoc-members: :members: mapper_method +Shift operators +--------------- + +.. autoclass:: LeftShift + :undoc-members: + :members: mapper_method + +.. autoclass:: RightShift + :undoc-members: + :members: mapper_method + +Bitwise operators +----------------- + +.. autoclass:: BitwiseNot + :undoc-members: + :members: mapper_method + +.. autoclass:: BitwiseOr + :undoc-members: + :members: mapper_method + +.. autoclass:: BitwiseXor + :undoc-members: + :members: mapper_method + +.. autoclass:: BitwiseAnd + :undoc-members: + :members: mapper_method + Comparisons and logic --------------------- diff --git a/pymbolic/mapper/__init__.py b/pymbolic/mapper/__init__.py index fa54fc8ffacd6761b1555b99b35ae77d07c536a8..cd56ad807b59c50a5339c9bac9b9a22cb2ac7024 100644 --- a/pymbolic/mapper/__init__.py +++ b/pymbolic/mapper/__init__.py @@ -186,14 +186,22 @@ class CombineMapper(RecursiveMapper): self.rec(coeff, *args) for exp, coeff in expr.data) ) - def map_logical_and(self, expr, *args): - return self.combine(self.rec(child, *args) - for child in expr.children) + def map_left_shift(self, expr, *args): + return self.combine( + self.rec(expr.shiftee, *args), + self.rec(expr.shift, *args)) - map_logical_or = map_logical_and + map_right_shift = map_left_shift - def map_logical_not(self, expr, *args): + def map_bitwise_not(self, expr, *args): return self.rec(expr.child, *args) + map_bitwise_or = map_sum + map_bitwise_xor = map_sum + map_bitwise_and = map_sum + + map_logical_not = map_bitwise_not + map_logical_and = map_sum + map_logical_or = map_sum def map_comparison(self, expr, *args): return self.combine(( @@ -288,16 +296,27 @@ class IdentityMapper(Mapper): ((exp, self.rec(coeff, *args)) for exp, coeff in expr.data)) - def map_logical_and(self, expr, *args): + def map_left_shift(self, expr, *args): + return type(expr)( + self.rec(expr.shiftee, *args), + self.rec(expr.shift, *args)) + + map_right_shift = map_left_shift + + def map_bitwise_not(self, expr, *args): + return type(expr)( + self.rec(expr.child, *args)) + + def map_bitwise_or(self, expr, *args): return type(expr)(tuple( self.rec(child, *args) for child in expr.children)) - map_logical_or = map_logical_and + map_bitwise_xor = map_bitwise_or + map_bitwise_and = map_bitwise_or - def map_logical_not(self, expr, *args): - from pymbolic.primitives import LogicalNot - return LogicalNot( - self.rec(expr.child, *args)) + map_logical_not = map_bitwise_not + map_logical_or = map_bitwise_or + map_logical_and = map_bitwise_or def map_comparison(self, expr, *args): return type(expr)( @@ -463,19 +482,33 @@ class WalkMapper(RecursiveMapper): self.rec(expr.child) - def map_comparison(self, expr): + def map_left_shift(self, expr): if not self.visit(expr): return - self.rec(expr.left) - self.rec(expr.right) + self.rec(expr.shift) + self.rec(expr.shiftee) + + mrs = map_left_shift - def map_logical_not(self, expr): + def map_bitwise_not(self, expr): if not self.visit(expr): return self.rec(expr.child) + map_bitwise_or = map_sum + map_bitwise_xor = map_sum + map_bitwise_and = map_sum + + def map_comparison(self, expr): + if not self.visit(expr): + return + + self.rec(expr.left) + self.rec(expr.right) + + map_logical_not = map_bitwise_not map_logical_and = map_sum map_logical_or = map_sum @@ -537,6 +570,19 @@ class CallbackMapper(RecursiveMapper): map_floor_div = map_constant map_remainder = map_constant map_power = map_constant + + map_left_shift = map_constant + map_right_shift = map_constant + + map_bitwise_not = map_constant + map_bitwise_or = map_constant + map_bitwise_xor = map_constant + map_bitwise_and = map_constant + + map_logical_not = map_constant + map_logical_or = map_constant + map_logical_and = map_constant + map_polynomial = map_constant map_list = map_constant map_tuple = map_constant diff --git a/pymbolic/mapper/c_code.py b/pymbolic/mapper/c_code.py index 61ed0f3218540c496b5a7ff4d9d92d9ef167a3cf..c18d0977fbc3c60b649251570d71879aed5b7027 100644 --- a/pymbolic/mapper/c_code.py +++ b/pymbolic/mapper/c_code.py @@ -22,7 +22,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from pymbolic.mapper.stringifier import SimplifyingSortingStringifyMapper +from pymbolic.mapper.stringifier import ( + SimplifyingSortingStringifyMapper, PREC_UNARY, + PREC_LOGICAL_AND, PREC_LOGICAL_OR) class CCodeMapper(SimplifyingSortingStringifyMapper): @@ -83,7 +85,8 @@ class CCodeMapper(SimplifyingSortingStringifyMapper): def copy_with_mapped_cses(self, cses_and_values): return self.copy(self.cse_name_list + cses_and_values) - # mappings ---------------------------------------------------------------- + # {{{ mappings + def map_product(self, expr, enclosing_prec): from pymbolic.mapper.stringifier import PREC_PRODUCT return self.parenthesize_if_needed( @@ -139,6 +142,21 @@ class CCodeMapper(SimplifyingSortingStringifyMapper): self.rec(expr.numerator, PREC_PRODUCT), self.rec(expr.denominator, PREC_POWER)) # analogous to ^{-1} + def map_logical_not(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + "!" + self.rec(expr.child, PREC_UNARY), + enclosing_prec, PREC_UNARY) + + def map_logical_and(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + self.join_rec(" && ", expr.children, PREC_LOGICAL_AND), + enclosing_prec, PREC_LOGICAL_AND) + + def map_logical_or(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + self.join_rec(" || ", expr.children, PREC_LOGICAL_OR), + enclosing_prec, PREC_LOGICAL_OR) + def map_common_subexpression(self, expr, enclosing_prec): try: cse_name = self.cse_to_name[expr.child] @@ -187,3 +205,4 @@ class CCodeMapper(SimplifyingSortingStringifyMapper): self.rec(expr.then, PREC_NONE), self.rec(expr.else_, PREC_NONE), ) + # }}} diff --git a/pymbolic/mapper/evaluator.py b/pymbolic/mapper/evaluator.py index 5ef2019f5f00b266776c4705f91ab49e64b489b1..c4ef3f64f8c3e3a401239e08db188c020b6ecaa5 100644 --- a/pymbolic/mapper/evaluator.py +++ b/pymbolic/mapper/evaluator.py @@ -22,7 +22,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ + from pymbolic.mapper import RecursiveMapper +import operator as op class UnknownVariableError(Exception): @@ -90,6 +92,35 @@ class EvaluationMapper(RecursiveMapper): def map_power(self, expr): return self.rec(expr.base) ** self.rec(expr.exponent) + def map_left_shift(self, expr): + return self.rec(expr.shiftee) << self.rec(expr.shift) + + def map_right_shift(self, expr): + return self.rec(expr.shiftee) >> self.rec(expr.shift) + + def map_bitwise_not(self, expr): + return ~self.rec(expr.child) + + def map_bitwise_or(self, expr): + return reduce(op.or_, (self.rec(ch) for ch in expr.children)) + + def map_bitwise_xor(self, expr): + return reduce(op.xor, (self.rec(ch) for ch in expr.children)) + + def map_bitwise_and(self, expr): + return reduce(op.and_, (self.rec(ch) for ch in expr.children)) + + def map_logical_not(self, expr): + return not self.rec(expr.child) + + def map_logical_or(self, expr): + from pytools import any + return any(self.rec(ch) for ch in expr.children) + + def map_logical_and(self, expr): + from pytools import all + return all(self.rec(ch) for ch in expr.children) + def map_polynomial(self, expr): # evaluate using Horner's scheme result = 0 diff --git a/pymbolic/mapper/stringifier.py b/pymbolic/mapper/stringifier.py index 4e2f029650e2ff6eeb416b8585094383c231de6f..719869b13956bb1311ce06295aa6863d63a892ce 100644 --- a/pymbolic/mapper/stringifier.py +++ b/pymbolic/mapper/stringifier.py @@ -30,9 +30,13 @@ PREC_POWER = 14 PREC_UNARY = 13 PREC_PRODUCT = 12 PREC_SUM = 11 -PREC_COMPARISON = 10 -PREC_LOGICAL_AND = 9 -PREC_LOGICAL_OR = 8 +PREC_SHIFT = 10 +PREC_BITWISE_AND = 9 +PREC_BITWISE_XOR = 8 +PREC_BITWISE_OR = 7 +PREC_COMPARISON = 6 +PREC_LOGICAL_AND = 5 +PREC_LOGICAL_OR = 4 PREC_NONE = 0 @@ -167,6 +171,40 @@ class StringifyMapper(pymbolic.mapper.Mapper): [coeff*expr.base**exp for exp, coeff in expr.data[::-1]]), enclosing_prec) + def map_left_shift(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + self.format("%s << %s", + self.rec(expr.shiftee, PREC_SHIFT), + self.rec(expr.shift, PREC_SHIFT)), + enclosing_prec, PREC_SHIFT) + + def map_right_shift(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + self.format("%s >> %s", + self.rec(expr.shiftee, PREC_SHIFT), + self.rec(expr.shift, PREC_SHIFT)), + enclosing_prec, PREC_SHIFT) + + def map_bitwise_not(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + "~" + self.rec(expr.child, PREC_UNARY), + enclosing_prec, PREC_UNARY) + + def map_bitwise_or(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + self.join_rec(" | ", expr.children, PREC_BITWISE_OR), + enclosing_prec, PREC_BITWISE_OR) + + def map_bitwise_xor(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + self.join_rec(" ^ ", expr.children, PREC_BITWISE_XOR), + enclosing_prec, PREC_BITWISE_XOR) + + def map_bitwise_and(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + self.join_rec(" ^ ", expr.children, PREC_BITWISE_AND), + enclosing_prec, PREC_BITWISE_AND) + def map_comparison(self, expr, enclosing_prec): return self.parenthesize_if_needed( self.format("%s %s %s", @@ -177,19 +215,19 @@ class StringifyMapper(pymbolic.mapper.Mapper): def map_logical_not(self, expr, enclosing_prec): return self.parenthesize_if_needed( - self.rec(expr.child, PREC_UNARY), + "not " + self.rec(expr.child, PREC_UNARY), enclosing_prec, PREC_UNARY) - def map_logical_and(self, expr, enclosing_prec): - return self.parenthesize_if_needed( - self.join_rec(" && ", expr.children, PREC_LOGICAL_AND), - enclosing_prec, PREC_LOGICAL_AND) - def map_logical_or(self, expr, enclosing_prec): return self.parenthesize_if_needed( - self.join_rec(" || ", expr.children, PREC_LOGICAL_OR), + self.join_rec(" or ", expr.children, PREC_LOGICAL_OR), enclosing_prec, PREC_LOGICAL_OR) + def map_logical_and(self, expr, enclosing_prec): + return self.parenthesize_if_needed( + self.join_rec(" and ", expr.children, PREC_LOGICAL_AND), + enclosing_prec, PREC_LOGICAL_AND) + def map_list(self, expr, enclosing_prec): return self.format("[%s]", self.join_rec(", ", expr, PREC_NONE)) diff --git a/pymbolic/primitives.py b/pymbolic/primitives.py index 68a6c291e83d1709c7fa2ccf71b820365c8a7f1c..ab3974178bb1108a452b21ee65f1db40896cd28a 100644 --- a/pymbolic/primitives.py +++ b/pymbolic/primitives.py @@ -167,6 +167,49 @@ class Expression(object): # }}} + # {{{ shifts + + def __lshift__(self, other): + return LeftShift(self, other) + + def __rlshift__(self, other): + return LeftShift(other, self) + + def __rshift__(self, other): + return RightShift(self, other) + + def __rrshift__(self, other): + return RightShift(other, self) + + # }}} + + # {{{ bitwise operators + + def __inv__(self): + return BitwiseNot(self) + + def __or__(self, other): + return BitwiseOr(self, other) + + def __ror__(self, other): + return BitwiseOr(other, self) + + def __xor__(self, other): + return BitwiseXor(self, other) + + def __rxor__(self, other): + return BitwiseXor(other, self) + + def __and__(self, other): + return BitwiseAnd(self, other) + + def __rand__(self, other): + return BitwiseAnd(other, self) + + # }}} + + # {{{ + def __neg__(self): return -1*self @@ -211,6 +254,7 @@ class Expression(object): initargs_str = ", ".join(repr(i) for i in self.__getinitargs__()) return "%s(%s)" % (self.__class__.__name__, initargs_str) + # }}} # {{{ hashable interface @@ -396,13 +440,7 @@ class Lookup(AlgebraicLeaf): # {{{ arithmetic primitives -class Sum(Expression): - """ - .. attribute:: children - - A :class:`tuple`. - """ - +class _MultiChildExpression(Expression): def __init__(self, children): assert isinstance(children, tuple) @@ -411,6 +449,14 @@ class Sum(Expression): def __getinitargs__(self): return self.children + +class Sum(_MultiChildExpression): + """ + .. attribute:: children + + A :class:`tuple`. + """ + def __add__(self, other): if not is_valid_operand(other): return NotImplemented @@ -451,20 +497,13 @@ class Sum(Expression): mapper_method = intern("map_sum") -class Product(Expression): +class Product(_MultiChildExpression): """ .. attribute:: children A :class:`tuple`. """ - def __init__(self, children): - assert isinstance(children, tuple) - self.children = children - - def __getinitargs__(self): - return self.children - def __mul__(self, other): if not is_valid_operand(other): return NotImplemented @@ -567,6 +606,85 @@ class Power(Expression): # }}} +# {{{ shift operators + +class _ShiftOperator(Expression): + def __init__(self, shiftee, shift): + self.shiftee = shiftee + self.shift = shift + + def __getinitargs__(self): + return self.base, self.exponent + + +class LeftShift(Expression): + """ + .. attribute:: shiftee + .. attribute:: shift + """ + + mapper_method = intern("map_left_shift") + + +class RightShift(Expression): + """ + .. attribute:: shiftee + .. attribute:: shift + """ + + mapper_method = intern("map_right_shift") + +# }}} + + +# {{{ bitwise operators + +class BitwiseNot(Expression): + """ + .. attribute:: child + """ + + def __init__(self, child): + self.child = child + + def __getinitargs__(self): + return (self.child,) + + mapper_method = intern("map_bitwise_not") + + +class BitwiseOr(_MultiChildExpression): + """ + .. attribute:: children + + A :class:`tuple`. + """ + + mapper_method = intern("map_bitwise_or") + + +class BitwiseXor(_MultiChildExpression): + """ + .. attribute:: children + + A :class:`tuple`. + """ + + mapper_method = intern("map_bitwise_xor") + + +class BitwiseAnd(_MultiChildExpression): + """ + .. attribute:: children + + A :class:`tuple`. + """ + + mapper_method = intern("map_bitwise_and") + +# }}} + + # {{{ comparisons, logic, conditionals class ComparisonOperator(Expression): @@ -598,11 +716,7 @@ class ComparisonOperator(Expression): mapper_method = intern("map_comparison") -class BooleanExpression(Expression): - pass - - -class LogicalNot(BooleanExpression): +class LogicalNot(Expression): """ .. attribute:: child """ @@ -611,44 +725,28 @@ class LogicalNot(BooleanExpression): self.child = child def __getinitargs__(self): - return (self.child, self.prefix) + return (self.child,) mapper_method = intern("map_logical_not") -class LogicalOr(BooleanExpression): +class LogicalOr(_MultiChildExpression): """ .. attribute:: children A :class:`tuple`. """ - def __init__(self, children): - assert isinstance(children, tuple) - - self.children = children - - def __getinitargs__(self): - return self.children - mapper_method = intern("map_logical_or") -class LogicalAnd(BooleanExpression): +class LogicalAnd(_MultiChildExpression): """ .. attribute:: children A :class:`tuple`. """ - def __init__(self, children): - assert isinstance(children, tuple) - - self.children = children - - def __getinitargs__(self): - return self.children - mapper_method = intern("map_logical_and")