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
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:])
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:])
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]
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
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)
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]
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")
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
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