Ejemplo n.º 1
0
def convert_to_int(source):
    """Convert source to integer or fail."""
    if isinstance(source, str):
        return interpret_int(source)
    if isinstance(source, int):
        return interpret_int(str(source))
    return source
Ejemplo n.º 2
0
def convert_to_int(source):
    """Convert source to integer or fail."""
    if isinstance(source, str):
        return interpret_int(source)
    if isinstance(source, int):
        return interpret_int(str(source))
    return source
Ejemplo n.º 3
0
 def applyOperator(self, oper, left_token, right_token):
     """Apply operator, collapsing into one number if possible."""
     left = left_token.getSingleChild()
     right = right_token.getSingleChild()
     if (not is_glsl_number(left)) or (not is_glsl_number(right)):
         return None
     # Resolve to float if either is a float.
     if is_glsl_float(left) or is_glsl_float(right):
         left_number = left.getFloat()
         right_number = right.getFloat()
     else:
         left_number = left.getInt()
         right_number = right.getInt()
     if (left_number is None) or (right_number is None):
         raise RuntimeError("error getting number values")
     # Perform operation.
     result_number = oper.applyOperator(left_number, right_number)
     # Replace content of this with the result number
     if is_glsl_float(left) or is_glsl_float(right):
         number_string = str(float(result_number))
         (integer_part, decimal_part) = number_string.split(".")
         result_number = interpret_float(integer_part, decimal_part)
     else:
         result_number = interpret_int(str(result_number))
     # Not all operations require truncation afterwards.
     if oper.requiresTruncation():
         lower_precision = min(left.getPrecision(),
                               right.getPrecision()) + 1
         precision = max(max(left.getPrecision(), right.getPrecision()),
                         lower_precision)
         result_number.truncatePrecision(precision)
     return result_number
Ejemplo n.º 4
0
 def applyOperator(self, oper, left_token, right_token):
     """Apply operator, collapsing into one number if possible."""
     left = left_token.getSingleChild()
     right = right_token.getSingleChild()
     if (not is_glsl_number(left)) or (not is_glsl_number(right)):
         return None
     # Resolve to float if either is a float.
     if is_glsl_float(left) or is_glsl_float(right):
         left_number = left.getFloat()
         right_number = right.getFloat()
     else:
         left_number = left.getInt()
         right_number = right.getInt()
     if (left_number is None) or (right_number is None):
         raise RuntimeError("error getting number values")
     # Perform operation.
     result_number = oper.applyOperator(left_number, right_number)
     # Replace content of this with the result number
     if is_glsl_float(left) or is_glsl_float(right):
         number_string = str(float(result_number))
         (integer_part, decimal_part) = number_string.split(".")
         result_number = interpret_float(integer_part, decimal_part)
     else:
         result_number = interpret_int(str(result_number))
     # Not all operations require truncation afterwards.
     if oper.requiresTruncation():
         lower_precision = min(left.getPrecision(), right.getPrecision()) + 1
         precision = max(max(left.getPrecision(), right.getPrecision()), lower_precision)
         result_number.truncatePrecision(precision)
     return result_number
Ejemplo n.º 5
0
 def truncatePrecision(self, op):
     """Truncate numeric precision to some value of expressed numbers."""
     used = self.__integer1.truncatePrecision(op)
     if used >= op:
         self.__integer2 = interpret_int("0")
     else:
         self.__integer2.truncatePrecision(op - used)
     self.updateNumber()
Ejemplo n.º 6
0
 def truncatePrecision(self, op):
     """Truncate numeric precision to some value of expressed numbers."""
     used = self.__integer1.truncatePrecision(op)
     if used >= op:
         self.__integer2 = interpret_int("0")
     else:
         self.__integer2.truncatePrecision(op - used)
     self.updateNumber()
Ejemplo n.º 7
0
def tokenize_interpret(tokens):
    """Interpret a list of preliminary tokens, assembling constructs from them."""
    ret = []
    ii = 0
    while len(tokens) > ii:
        element = tokens[ii]
        # Try paren.
        paren = interpret_paren(element)
        if paren:
            ret += [paren]
            ii += 1
            continue
        # Try 2-stage control.
        if (ii + 1) < len(tokens):
            control = interpret_control(element, tokens[ii + 1])
            if control:
                ret += [control]
                ii += 2
                continue
        # Try control.
        control = interpret_control(element)
        if control:
            ret += [control]
            ii += 1
            continue
        # Try in/out.
        inout = interpret_inout(element)
        if inout:
            ret += [inout]
            ii += 1
            continue
        # Try 2-stage type.
        if (ii + 1) < len(tokens):
            typeid = interpret_type(element, tokens[ii + 1])
            if typeid:
                ret += [typeid]
                ii += 2
                continue
        # Try type.
        typeid = interpret_type(element)
        if typeid:
            ret += [typeid]
            ii += 1
            continue
        # Period may signify truncated floating point or member/swizzle access.
        if "." == tokens[ii] and (ii + 1) < len(tokens):
            decimal = interpret_int(tokens[ii + 1])
            if decimal:
                ret += [interpret_float(0, decimal)]
                ii += 2
                continue
            access = interpret_access(tokens[ii + 1])
            if access:
                access.setSource(ret)
                ret += [access]
                ii += 2
                continue
        # Number may be just an integer or floating point.
        number = interpret_int(element)
        if number:
            if (ii + 1) < len(tokens) and "." == tokens[ii + 1]:
                if (ii + 2) < len(tokens):
                    decimal = interpret_int(tokens[ii + 2])
                    if decimal:
                        ret += [interpret_float(number, decimal)]
                        ii += 3
                        continue
                ret += [interpret_float(number, 0)]
                ii += 2
                continue
            ret += [number]
            ii += 1
            continue
        # Special characters may be operators, up to two in a row.
        operator = interpret_operator(element)
        if operator:
            if (ii + 1) < len(tokens):
                extended_operator = interpret_operator(tokens[ii + 1])
                if extended_operator and operator.incorporate(
                        extended_operator):
                    ret += [operator]
                    ii += 2
                    continue
            ret += [operator]
            ii += 1
            continue
        # Statement terminator.
        terminator = interpret_terminator(element)
        if terminator:
            ret += [terminator]
            ii += 1
            continue
        # Try name identifier last.
        name = interpret_name(element)
        if name:
            ret += [name]
            ii += 1
            continue
        # Fallback is to add token as-is.
        print("WARNING: GLSL: unknown element '%s'" % element)
        ret += [element]
        ii += 1
    return ret
Ejemplo n.º 8
0
 def simplify(self):
     """Perform any simple simplification and stop."""
     # Remove parens.
     if self.isSurroundedByParens():
         middle_lst = self.flattenMiddle()
         #debug_str = " ".join(map(lambda x: str(x), middle_lst))
         #if debug_str.find("normalize") > -1:
         #  print(debug_str)
         # Single expression.
         if len(middle_lst) == 1:
             if self.removeParens():
                 return True
         # Number or name with access.
         elif len(middle_lst) == 2:
             mid_lt = middle_lst[0]
             mid_rt = middle_lst[1]
             if (is_glsl_name(mid_lt)
                     or is_glsl_number(mid_lt)) and is_glsl_access(mid_rt):
                 if self.removeParens():
                     return True
         # Single function call or indexing (with potential access).
         elif len(middle_lst) >= 3:
             mid_name = middle_lst[0]
             mid_opening = middle_lst[1]
             last_index = -1
             mid_ending = middle_lst[last_index]
             # If last part is access, try the element before that instead.
             if is_glsl_access(mid_ending) and (len(middle_lst) >= 4):
                 last_index = -2
                 mid_ending = middle_lst[last_index]
             # Check for function call or indexing format.
             if (is_glsl_name(mid_name)
                     or is_glsl_type(mid_name)) and is_glsl_paren(
                         mid_opening) and mid_opening.matches(mid_ending):
                 if is_single_call_or_access_list(middle_lst[2:last_index],
                                                  mid_opening):
                     if self.removeParens():
                         return True
         # Only contains lower-priority operators compared to outside.
         paren_rt = self.__right[0].getSingleChild()
         elem_rt = self.findRightSiblingElementFromParentTree(paren_rt)
         prio = self.findHighestPrioOperatorMiddle()
         # Right element cannot be access or bracket.
         if (prio >= 0) and (not is_glsl_access(elem_rt)) and (elem_rt !=
                                                               "["):
             left = self.findSiblingOperatorLeft()
             right = self.findSiblingOperatorRight()
             if left:
                 if left.getPrecedence() > prio:
                     if right:
                         if right.getPrecedence() >= prio:
                             if self.removeParens():
                                 return True
                     else:
                         if self.removeParens():
                             return True
             elif right:
                 if right.getPrecedence() >= prio:
                     if self.removeParens():
                         return True
             else:
                 if self.removeParens():
                     return True
     # Recurse down.
     for ii in self.__left:
         if ii.simplify():
             return True
     for ii in self.__right:
         if ii.simplify():
             return True
     for ii in self.__middle:
         if is_glsl_token(ii):
             if ii.simplify():
                 return True
     # Perform operations only after removing any possible parens.
     if (len(self.__middle) == 1):
         oper = self.__middle[0]
         if is_glsl_operator(oper) and oper.isApplicable():
             # Try to remove trivial cases.
             if self.collapseIdentity():
                 return True
             (left_parent, left_token) = self.findEqualTokenLeft(self)
             (right_parent, right_token) = self.findEqualTokenRight(self)
             if left_parent and left_token and right_parent and right_token:
                 # Trivial case - leaf entry that can just be applied.
                 if left_parent is right_parent:
                     if not (left_parent is self):
                         raise RuntimeError(
                             "left and right operator resolve as '%s' not matching self '%s'"
                             % (str(left_parent), str(self)))
                     result = self.applyOperator(oper, left_token,
                                                 right_token)
                     if not (result is None):
                         # Remove sides from parent.
                         left_token.removeFromParent()
                         right_token.removeFromParent()
                         self.__middle = [result]
                         return True
                 # Nontrivial cases.
                 left_oper = left_parent.getSingleChildMiddleNonToken()
                 right_oper = right_parent.getSingleChildMiddleNonToken()
                 result = None
                 # Double divide -> multiply.
                 if (left_oper == "/") and (
                         right_oper
                         == "/") and left_token.isSingleChildRight():
                     result = self.applyOperator(interpret_operator("*"),
                                                 left_token, right_token)
                 # Same operation -> can be just applied.
                 elif left_parent == right_parent:
                     result = self.applyOperator(left_oper, left_token,
                                                 right_token)
                 # Substract addition: <something> - a + b => <something> + (b - a)
                 elif (left_oper
                       == "-") and (oper == "+") and (oper is right_oper):
                     result = self.applyOperator(left_oper, right_token,
                                                 left_token)
                     # If b - a is negative, replace it with its absolute value which is going to get subtracted.
                     if result.getFloat() < 0.0:
                         right_oper.setOperator("-")
                         if is_glsl_int(result):
                             result = interpret_int(
                                 str(abs(result.getInt())))
                         elif is_glsl_float(result):
                             number_string = str(abs(result.getFloat()))
                             (integer_part,
                              decimal_part) = number_string.split(".")
                             result = interpret_float(
                                 integer_part, decimal_part)
                         else:
                             raise RuntimeError(
                                 "unknown result object '%s'" %
                                 (str(result)))
                 # TODO: further cases.
                 # On success, eliminate upper token (left only if necessary) and replace other token with result.
                 if result:
                     if left_parent is self:
                         right_token.collapseUp()
                         left_token.replaceMiddle(result)
                     else:
                         left_token.collapseUp()
                         right_token.replaceMiddle(result)
                     return True
     # Operations are done. Allow simplification of remaining constans, if possible.
     mid = self.getSingleChildMiddleNonToken()
     if mid and is_glsl_float(mid) and (not mid.isIntegrifyAllowed()):
         # No operators, left or right.
         left = self.findSiblingOperatorLeft()
         right = self.findSiblingOperatorRight()
         if not left and not right:
             mid.setAllowIntegrify(True)
             return True
         # Alone in vecN() directive.
         left = self.getSingleChildLeft()
         right = self.getSingleChildRight()
         if left and left.isTypeOpen() and right and (
                 right.getSingleChildMiddleNonToken() == ")"):
             mid.setAllowIntegrify(True)
             return True
         # If could not be integrified, at least ensure that float precision is not exceeded.
         if mid.getPrecision() > 6:
             mid.truncatePrecision(6)
             return True
     return False
Ejemplo n.º 9
0
def tokenize_interpret(tokens):
    """Interpret a list of preliminary tokens, assembling constructs from them."""
    ret = []
    ii = 0
    while len(tokens) > ii:
        element = tokens[ii]
        # Try paren.
        paren = interpret_paren(element)
        if paren:
            ret += [paren]
            ii += 1
            continue
        # Try 2-stage control.
        if (ii + 1) < len(tokens):
            control = interpret_control(element, tokens[ii + 1])
            if control:
                ret += [control]
                ii += 2
                continue
        # Try control.
        control = interpret_control(element)
        if control:
            ret += [control]
            ii += 1
            continue
        # Try in/out.
        inout = interpret_inout(element)
        if inout:
            ret += [inout]
            ii += 1
            continue
        # Try 2-stage type.
        if (ii + 1) < len(tokens):
            typeid = interpret_type(element, tokens[ii + 1])
            if typeid:
                ret += [typeid]
                ii += 2
                continue
        # Try type.
        typeid = interpret_type(element)
        if typeid:
            ret += [typeid]
            ii += 1
            continue
        # Period may signify truncated floating point or member/swizzle access.
        if "." == tokens[ii] and (ii + 1) < len(tokens):
            decimal = interpret_int(tokens[ii + 1])
            if decimal:
                ret += [interpret_float(0, decimal)]
                ii += 2
                continue
            access = interpret_access(tokens[ii + 1])
            if access:
                access.setSource(ret)
                ret += [access]
                ii += 2
                continue
        # Number may be just an integer or floating point.
        number = interpret_int(element)
        if number:
            if (ii + 1) < len(tokens) and "." == tokens[ii + 1]:
                if (ii + 2) < len(tokens):
                    decimal = interpret_int(tokens[ii + 2])
                    if decimal:
                        ret += [interpret_float(number, decimal)]
                        ii += 3
                        continue
                ret += [interpret_float(number, 0)]
                ii += 2
                continue
            ret += [number]
            ii += 1
            continue
        # Special characters may be operators, up to two in a row.
        operator = interpret_operator(element)
        if operator:
            if (ii + 1) < len(tokens):
                extended_operator = interpret_operator(tokens[ii + 1])
                if extended_operator and operator.incorporate(extended_operator):
                    ret += [operator]
                    ii += 2
                    continue
            ret += [operator]
            ii += 1
            continue
        # Statement terminator.
        terminator = interpret_terminator(element)
        if terminator:
            ret += [terminator]
            ii += 1
            continue
        # Try name identifier last.
        name = interpret_name(element)
        if name:
            ret += [name]
            ii += 1
            continue
        # Fallback is to add token as-is.
        print("WARNING: GLSL: unknown element '%s'" % element)
        ret += [element]
        ii += 1
    return ret
Ejemplo n.º 10
0
 def simplify(self):
     """Perform any simple simplification and stop."""
     # Remove parens.
     if self.isSurroundedByParens():
         middle_lst = self.flattenMiddle()
         # Single expression.
         if len(middle_lst) == 1:
             if self.removeParens():
                 return True
         # Number or name with access.
         elif len(middle_lst) == 2:
             mid_lt = middle_lst[0]
             mid_rt = middle_lst[1]
             if (is_glsl_name(mid_lt) or is_glsl_number(mid_lt)) and is_glsl_access(mid_rt):
                 if self.removeParens():
                     return True
         # Single function call or indexing (with potential access).
         elif len(middle_lst) >= 3:
             mid_name = middle_lst[0]
             mid_opening = middle_lst[1]
             last_index = -1
             mid_ending = middle_lst[last_index]
             # If last part is access, try the element before that instead.
             if is_glsl_access(mid_ending) and (len(middle_lst) >= 4):
                 last_index = -2
                 mid_ending = middle_lst[last_index]
             # Check for function call or indexing format.
             if (is_glsl_name(mid_name) or is_glsl_type(mid_name)) and is_glsl_paren(mid_opening) and mid_opening.matches(mid_ending):
                 if is_single_call_or_access_list(middle_lst[2:last_index], mid_opening):
                     if self.removeParens():
                         return True
         # Only contains lower-priority operators compared to outside.
         paren_rt = self.__right[0].getSingleChild()
         elem_rt = self.findRightSiblingElementFromParentTree(paren_rt)
         prio = self.findHighestPrioOperatorMiddle()
         # Right element cannot be access or bracket.
         if (prio >= 0) and (not is_glsl_access(elem_rt)) and (elem_rt != "["):
             left = self.findSiblingOperatorLeft()
             right = self.findSiblingOperatorRight()
             if left:
                 if left.getPrecedence() > prio:
                     if right:
                         if right.getPrecedence() >= prio:
                             if self.removeParens():
                                 return True
                     else:
                         if self.removeParens():
                             return True
             elif right:
                 if right.getPrecedence() >= prio:
                     if self.removeParens():
                         return True
             else:
                 if self.removeParens():
                     return True
     # Recurse down.
     for ii in self.__left:
         if ii.simplify():
             return True
     for ii in self.__right:
         if ii.simplify():
             return True
     for ii in self.__middle:
         if is_glsl_token(ii):
             if ii.simplify():
                 return True
     # Perform operations only after removing any possible parens.
     if (len(self.__middle) == 1):
         oper = self.__middle[0]
         if is_glsl_operator(oper) and oper.isApplicable():
             # Try to remove trivial cases.
             if self.collapseIdentity():
                 return True
             (left_parent, left_token) = self.findEqualTokenLeft(self)
             (right_parent, right_token) = self.findEqualTokenRight(self)
             if left_parent and left_token and right_parent and right_token:
                 # Trivial case - leaf entry that can just be applied.
                 if left_parent is right_parent:
                     if not (left_parent is self):
                         raise RuntimeError("left and right operator resolve as '%s' not matching self '%s'" %
                                            (str(left_parent), str(self)))
                     result = self.applyOperator(oper, left_token, right_token)
                     if not (result is None):
                         # Remove sides from parent.
                         left_token.removeFromParent()
                         right_token.removeFromParent()
                         self.__middle = [result]
                         return True
                 # Nontrivial cases.
                 left_oper = left_parent.getSingleChildMiddleNonToken()
                 right_oper = right_parent.getSingleChildMiddleNonToken()
                 result = None
                 # Double divide -> multiply.
                 if (left_oper == "/") and (right_oper == "/") and left_token.isSingleChildRight():
                     result = self.applyOperator(interpret_operator("*"), left_token, right_token)
                 # Same operation -> can be just applied.
                 elif left_parent == right_parent:
                     result = self.applyOperator(left_oper, left_token, right_token)
                 # Substract addition: <something> - a + b => <something> + (b - a)
                 elif (left_oper == "-") and (oper == "+") and (oper is right_oper):
                     result = self.applyOperator(left_oper, right_token, left_token)
                     # If b - a is negative, replace it with its absolute value which is going to get subtracted.
                     if result.getFloat() < 0.0:
                         right_oper.setOperator("-")
                         if is_glsl_int(result):
                             result = interpret_int(str(abs(result.getInt())))
                         elif is_glsl_float(result):
                             number_string = str(abs(result.getFloat()))
                             (integer_part, decimal_part) = number_string.split(".")
                             result = interpret_float(integer_part, decimal_part)
                         else:
                             raise RuntimeError("unknown result object '%s'" % (str(result)))
                 # TODO: further cases.
                 # On success, eliminate upper token (left only if necessary) and replace other token with result.
                 if result:
                     if left_parent is self:
                         right_token.collapseUp()
                         left_token.replaceMiddle(result)
                     else:
                         left_token.collapseUp()
                         right_token.replaceMiddle(result)
                     return True
     # Operations are done. Allow simplification of remaining constans, if possible.
     mid = self.getSingleChildMiddleNonToken()
     if mid and is_glsl_float(mid) and (abs(mid.getFloat()) <= 2147483647.0) and (not mid.isIntegrifyAllowed()):
         # No operators, left or right.
         left = self.findSiblingOperatorLeft()
         right = self.findSiblingOperatorRight()
         if (not left) and (not right):
             mid.setAllowIntegrify(True)
             return True
         # Alone in vecN() directive.
         left = self.getSingleChildLeft()
         right = self.getSingleChildRight()
         if left and left.isTypeOpen() and right and (right.getSingleChildMiddleNonToken() == ")"):
             mid.setAllowIntegrify(True)
             return True
         # If could not be integrified, at least ensure that float precision is not exceeded.
         if mid.getPrecision() > 6:
             mid.truncatePrecision(6)
             return True
     return False