Exemple #1
0
def has_inline_conflict(parent, block, names, comparison=None):
    """Tell if given block has inline conflict."""
    # Iterate over statement names if comparison not present.
    if not comparison:
        for ii in block.getStatement().getTokens():
            if is_glsl_name(ii) and has_inline_conflict(
                    parent, block, names, ii):
                return True
        return False
    # Search for alterations of name.
    found = False
    uses = len(names)
    for ii in flatten(parent):
        if block == ii:
            found = True
        # If name is found used by this particular block, decrement uses. Can stop iteration at 0 uses.
        for jj in names:
            if ii.hasUsedNameExact(jj):
                uses -= 1
        if 0 >= uses:
            return False
        # Assignment into a name used by the statement makes inlining impossible.
        if found and is_glsl_block_assignment(
                ii) and ii.getName() == comparison:
            return True
    return False
Exemple #2
0
def token_tree_split_paren(lst, first, last):
    """Split token tree for parens."""
    # Read types, names or accesses left.
    left = [lst[first]]
    iter_left = first - 1
    while iter_left >= 0:
        prospect = lst[iter_left].getSingleChild()
        if is_glsl_access(prospect) or is_glsl_name(prospect) or is_glsl_type(
                prospect):
            left = [lst[iter_left]] + left
            iter_left -= 1
        else:
            break
    # Left may be multiple elements.
    if 1 < len(left):
        left = GlslToken(left)
    else:
        left = left[0]
    # It's ok to have empty parens, as opposed to empty brackets.
    middle = token_tree_build(lst[first + 1:last])
    right = lst[last]
    # Create split.
    ret = GlslToken(middle)
    ret.addLeft(left)
    ret.addRight(right)
    return token_tree_build(lst[:iter_left + 1] + [ret] + lst[last + 1:])
Exemple #3
0
def token_tree_split_paren(lst, first, last):
    """Split token tree for parens."""
    # Read types, names or accesses left.
    left = [lst[first]]
    iter_left = first - 1
    while iter_left >= 0:
        prospect = lst[iter_left].getSingleChild()
        if is_glsl_access(prospect) or is_glsl_name(prospect) or is_glsl_type(prospect):
            left = [lst[iter_left]] + left
            iter_left -= 1
        else:
            break
    # Left may be multiple elements.
    if 1 < len(left):
        left = GlslToken(left)
    else:
        left = left[0]
    # It's ok to have empty parens, as opposed to empty brackets.
    middle = token_tree_build(lst[first + 1:last])
    right = lst[last]
    # Create split.
    ret = GlslToken(middle)
    ret.addLeft(left)
    ret.addRight(right)
    return token_tree_build(lst[:iter_left + 1] + [ret] + lst[last + 1:])
Exemple #4
0
 def addNamesUsed(self, op):
     """Add given names as names used by this block."""
     if is_listing(op):
         for ii in op:
             self.addNamesUsed(ii)
         return
     if not is_glsl_name(op):
         return
     self.__names_used += [op]
Exemple #5
0
 def addNamesUsed(self, op):
     """Add given names as names used by this block."""
     if is_listing(op):
         for ii in op:
             self.addNamesUsed(ii)
         return
     if not is_glsl_name(op):
         return
     self.__names_used += [op]
Exemple #6
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
Exemple #7
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
Exemple #8
0
 def addNamesDeclared(self, op):
     """Add given names as names declared by this block."""
     if is_listing(op):
         for ii in op:
             self.addNamesDeclared(ii)
         return
     if not is_glsl_name(op):
         return
     if op in self.__names_declared:
         raise RuntimeError("declaring name '%s' twice" % (op))
     self.__names_declared.add(op)
Exemple #9
0
 def addNamesDeclared(self, op):
     """Add given names as names declared by this block."""
     if is_listing(op):
         for ii in op:
             self.addNamesDeclared(ii)
         return
     if not is_glsl_name(op):
         return
     if op in self.__names_declared:
         raise RuntimeError("declaring name '%s' twice" % (op))
     self.__names_declared.add(op)
Exemple #10
0
 def addName(self, name):
     """Append one name to the list."""
     if not is_glsl_name(name):
         raise RuntimeError("not a GLSL name: %s" % (str(name)))
     if (self.getNameCount() >= 1) and (name != self.__names[0]):
         raise RuntimeError("trying to append unrelated names: %s != %s" %
                            (str(self.__names[0]), str(name)))
     # Used and declared name lists may contain the exact same name.
     for ii in self.__names:
         if ii is name:
             return
     self.__names += [name]
Exemple #11
0
 def setSource(self, lst):
     """Set source name for access."""
     bracket_count = 0
     paren_count = 0
     for ii in reversed(range(len(lst))):
         vv = lst[ii]
         if is_glsl_paren(vv):
             if vv.isCurlyBrace():
                 raise RuntimeError("curly brace found while looking for source of member")
             paren_count = vv.updateParen(paren_count)
             bracket_count = vv.updateBracket(bracket_count)
         if (is_glsl_name(vv) or is_glsl_access(vv)) and (0 == bracket_count) and (0 == paren_count):
             self.__source = vv
             vv.setAccess(self)
             return
     raise RuntimeError("could not find source for access")
Exemple #12
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
Exemple #13
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