Пример #1
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
Пример #2
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
Пример #3
0
def validate_token(token, validation):
    """Validate that token matches given requirement."""
    # Unsigned int.
    if "u" == validation:
        if not is_glsl_int_unsigned(token):
            return None
    # Int.
    elif "i" == validation:
        if not is_glsl_int(token):
            return None
    # Float.
    elif "f" == validation:
        if not is_glsl_float(token):
            return None
    # Access.
    elif "a" == validation:
        if not is_glsl_access(token):
            return None
    # Operator =.
    elif validation in ("="):
        if (not is_glsl_operator(token)) or (not token.isAssignment()):
            return None
    # Control.
    elif "c" == validation:
        if not is_glsl_control(token):
            return None
    # In/out.
    elif "o" == validation:
        if not is_glsl_inout(token):
            return None
    # Operator.
    elif "p" == validation:
        if not is_glsl_operator(token):
            return None
    # Type.
    elif "t" == validation:
        if not is_glsl_type(token):
            return None
    # Terminator.
    elif ";" == validation:
        if not is_glsl_terminator(token):
            return None
    # Valid identifier name.
    elif "n" == validation:
        if not is_glsl_name(token):
            return None
    # Select from options.
    elif validation.find("|") >= 0:
        variations = list(filter(lambda x: x, validation.split("|")))
        if not check_token(token, variations):
            return None
    # Unknown validation.
    else:
        raise RuntimeError("unknown token request '%s'" % (validation))
    # On success, return token as-is.
    return token
Пример #4
0
def validate_token(token, validation):
    """Validate that token matches given requirement."""
    # Unsigned int.
    if "u" == validation:
        if not is_glsl_int_unsigned(token):
            return None
    # Int.
    elif "i" == validation:
        if not is_glsl_int(token):
            return None
    # Float.
    elif "f" == validation:
        if not is_glsl_float(token):
            return None
    # Access.
    elif "a" == validation:
        if not is_glsl_access(token):
            return None
    # Operator =.
    elif validation in ("="):
        if (not is_glsl_operator(token)) or (not token.isAssignment()):
            return None
    # Control.
    elif "c" == validation:
        if not is_glsl_control(token):
            return None
    # In/out.
    elif "o" == validation:
        if not is_glsl_inout(token):
            return None
    # Operator.
    elif "p" == validation:
        if not is_glsl_operator(token):
            return None
    # Type.
    elif "t" == validation:
        if not is_glsl_type(token):
            return None
    # Terminator.
    elif ";" == validation:
        if not is_glsl_terminator(token):
            return None
    # Valid identifier name.
    elif "n" == validation:
        if not is_glsl_name(token):
            return None
    # Select from options.
    elif validation.find("|") >= 0:
        variations = list(filter(lambda x: x, validation.split("|")))
        if not check_token(token, variations):
            return None
    # Unknown validation.
    else:
        raise RuntimeError("unknown token request '%s'" % (validation))
    # On success, return token as-is.
    return token
Пример #5
0
def is_glsl_number(op):
    """Tell if given object is a number."""
    if is_glsl_float(op) or is_glsl_int(op):
        return True
    return False
Пример #6
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
Пример #7
0
def is_glsl_number(op):
    """Tell if given object is a number."""
    if is_glsl_float(op) or is_glsl_int(op):
        return True
    return False
Пример #8
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