Squashed 'third_party/pycrc/' content from commit cb91196b9

Change-Id: Iaed6f7d683e3c11395f10f0724f973363aad2cdb
git-subtree-dir: third_party/pycrc
git-subtree-split: cb91196b920d1f892c05941ed470c7a80cba7596
diff --git a/pycrc/expr.py b/pycrc/expr.py
new file mode 100644
index 0000000..a15742c
--- /dev/null
+++ b/pycrc/expr.py
@@ -0,0 +1,398 @@
+#  pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+#  Copyright (c) 2017  Thomas Pircher  <tehpeh-web@tty1.net>
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to
+#  deal in the Software without restriction, including without limitation the
+#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+#  sell copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+#  IN THE SOFTWARE.
+
+
+"""
+This modules simplifies an expression.
+
+    import pycrc.expr as exp
+
+    my_expr = exp.Xor('var', exp.Parenthesis(exp.And('0x700', 4)))
+    print('"{}" -> "{}"'.format(my_expr, my_expr.simplify()))
+"""
+
+
+def _classify(val):
+    """
+    Creates a Terminal object if the parameter is a string or an integer.
+    """
+    if type(val) is int:
+        return Terminal(val)
+    if type(val) is str:
+        if val.isdigit():
+            return Terminal(int(val), val)
+        if val[:2].lower() == '0x':
+            return Terminal(int(val, 16), val)
+        return Terminal(val)
+    return val
+
+
+class Expression(object):
+    """
+    Base class for all expressions.
+    """
+    def is_int(self, val = None):
+        return False
+
+
+class Terminal(Expression):
+    """
+    A terminal object.
+    """
+    def __init__(self, val, pretty = None):
+        """
+        Construct a Terminal.
+        The val variable is usually a string or an integer. Integers may also
+        be passed as strings. The pretty-printer will use the string when
+        formatting the expression.
+        """
+        self.val = val
+        self.pretty = pretty
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        if self.pretty is None:
+            return str(self.val)
+        return self.pretty
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        return self
+
+    def is_int(self, val = None):
+        """
+        Return True if the value of this Terminal is an integer.
+        """
+        if type(self.val) is int:
+            return val is None or self.val == val
+        return False
+
+
+class FunctionCall(Expression):
+    """
+    Represent a function call
+    """
+    def __init__(self, name, args):
+        """
+        Construct a function call object.
+        """
+        self.name = _classify(name)
+        self.args = [_classify(arg) for arg in args]
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.name) + '(' + ', '.join([str(arg) for arg in self.args]) + ')'
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        args = [arg.simplify() for arg in self.args]
+        return FunctionCall(self.name, args)
+
+
+class Parenthesis(Expression):
+    """
+    Represent a pair of round brackets.
+    """
+    def __init__(self, val):
+        """
+        Construct a parenthesis object.
+        """
+        self.val = _classify(val)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        val = self.val.simplify()
+        if type(val) is Terminal:
+            return val
+        return Parenthesis(val)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return '(' + str(self.val) + ')'
+
+
+class Add(Expression):
+    """
+    Represent an addition of operands.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct an addition object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val + rhs.val)
+        if lhs.is_int(0):
+            return rhs
+        if rhs.is_int(0):
+            return lhs
+        return Add(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' + ' + str(self.rhs)
+
+
+class Sub(Expression):
+    """
+    Represent a subtraction of operands.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct subtraction object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val - rhs.val)
+        if lhs.is_int(0):
+            return rhs
+        if rhs.is_int(0):
+            return lhs
+        return Sub(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' - ' + str(self.rhs)
+
+
+class Mul(Expression):
+    """
+    Represent the multiplication of operands.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a multiplication object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val * rhs.val)
+        if lhs.is_int(0) or rhs.is_int(0):
+            return Terminal(0)
+        if lhs.is_int(1):
+            return rhs
+        if rhs.is_int(1):
+            return lhs
+        return Mul(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' * ' + str(self.rhs)
+
+
+class Shl(Expression):
+    """
+    Shift left operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a shift left object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val << rhs.val)
+        if lhs.is_int(0):
+            return Terminal(0)
+        if rhs.is_int(0):
+            return lhs
+        return Shl(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' << ' + str(self.rhs)
+
+
+class Shr(Expression):
+    """
+    Shift right operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a shift right object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val >> rhs.val)
+        if lhs.is_int(0):
+            return Terminal(0)
+        if rhs.is_int(0):
+            return lhs
+        return Shr(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' >> ' + str(self.rhs)
+
+
+class Or(Expression):
+    """
+    Logical or operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a logical and object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val | rhs.val)
+        if lhs.is_int(0):
+            return rhs
+        if rhs.is_int(0):
+            return lhs
+        return Or(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' | ' + str(self.rhs)
+
+
+class And(Expression):
+    """
+    Logical and operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a logical and object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val & rhs.val)
+        if lhs.is_int(0) or rhs.is_int(0):
+            return Terminal(0)
+        return And(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' & ' + str(self.rhs)
+
+
+class Xor(Expression):
+    """
+    Logical xor operation.
+    """
+    def __init__(self, lhs, rhs):
+        """
+        Construct a logical xor object.
+        """
+        self.lhs = _classify(lhs)
+        self.rhs = _classify(rhs)
+
+    def simplify(self):
+        """
+        Return a simplified version of this sub-expression.
+        """
+        lhs = self.lhs.simplify()
+        rhs = self.rhs.simplify()
+        if lhs.is_int() and rhs.is_int():
+            return Terminal(lhs.val ^ rhs.val)
+        if lhs.is_int(0):
+            return rhs
+        if rhs.is_int(0):
+            return lhs
+        return Xor(lhs, rhs)
+
+    def __str__(self):
+        """
+        Return the string expression of this object.
+        """
+        return str(self.lhs) + ' ^ ' + str(self.rhs)