def extract_scope(tokens, opener): """Extract scope from token list. Needs scope opener to already be extracted.""" if not is_glsl_paren(opener): raise RuntimeError("no opener passed to scope extraction") paren_count = 1 ret = [] for ii in range(len(tokens)): elem = tokens[ii] if is_glsl_paren(elem): paren_count = opener.update(elem, paren_count) if 0 >= paren_count: return (ret, tokens[ii + 1:]) ret += [elem] # Did not find closing scope element. return (None, tokens)
def glsl_parse_statement(source, explicit = True): """Parse statement block.""" bracket_count = 0 paren_count = 0 lst = [] for ii in range(len(source)): elem = source[ii] # Count all scope-y things. if is_glsl_paren(elem): bracket_count = elem.updateBracket(bracket_count) if bracket_count < 0: raise RuntimeError("negative bracket parity") paren_count = elem.updateParen(paren_count) if paren_count < 0: raise RuntimeError("negative paren parity") if elem.isCurlyBrace(): raise RuntimeError("scope declaration within statement") # Statement end. elif (elem.format(False) in (",", ";")) and (paren_count == 0) and (bracket_count == 0): return (GlslBlockStatement(lst, elem), source[ii + 1:]) # Element is going into the statement. lst += [elem] # Was ok to have a statement without a terminator. if not explicit: return (GlslBlockStatement(lst), []) # Could not detect statement for a reason or another. return (None, source)
def glsl_parse_statement(source, explicit=True): """Parse statement block.""" bracket_count = 0 paren_count = 0 lst = [] for ii in range(len(source)): elem = source[ii] # Count all scope-y things. if is_glsl_paren(elem): bracket_count = elem.updateBracket(bracket_count) if bracket_count < 0: raise RuntimeError("negative bracket parity") paren_count = elem.updateParen(paren_count) if paren_count < 0: raise RuntimeError("negative paren parity") if elem.isCurlyBrace(): raise RuntimeError("scope declaration within statement: %s", (str(map(lambda x: str(x), source)))) # Statement end. elif (elem.format(False) in (",", ";")) and (paren_count == 0) and (bracket_count == 0): return (GlslBlockStatement(lst, elem), source[ii + 1:]) # Element is going into the statement. lst += [elem] # Was ok to have a statement without a terminator. if not explicit: return (GlslBlockStatement(lst), []) # Could not detect statement for a reason or another. return (None, source)
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 glsl_split_parameter_list(source): """Splits parameter list on commas.""" paren_count = 0 ret = [] current_parameter = [] for ii in source: # Count parens. if is_glsl_paren(ii): paren_count = elem.updateParen(paren_count) if paren_count < 0: raise RuntimeError("negative paren parity") if elem.isCurlyBrace(): raise RuntimeError("scope declaration within parameter") # Split to next param if paren count is 0. if ("," == ii) and (paren_count == 0): ret += [current_parameter] current_parameter = [] else: current_parameter += [ii] if current_parameter: ret += [current_parameter] return ret
def token_tree_build(lst): """Builds and balances a token tree from given list.""" # Ensure all list elements are tokens. lst = token_list_create(lst) # Might be that everything is lost at this point. if not lst: return None # Start iteration over tokenized list. bracket_count = 0 paren_count = 0 first_bracket_index = -1 first_paren_index = -1 lowest_operator = None lowest_operator_index = -1 for ii in range(len(lst)): vv = lst[ii].getSingleChild() # Count parens. if is_glsl_paren(vv): # Bracket case. if vv.isBracket(): new_bracket_count = vv.updateBracket(bracket_count) if new_bracket_count == bracket_count: raise RuntimeError("wut?") bracket_count = new_bracket_count # Split on brackets reaching 0. if 0 >= bracket_count: if 0 > first_bracket_index: raise RuntimeError("bracket inconsistency") return token_tree_split_paren(lst, first_bracket_index, ii) elif (1 == bracket_count) and (0 > first_bracket_index): first_bracket_index = ii # Paren case. elif vv.isParen(): new_paren_count = vv.updateParen(paren_count) if new_paren_count == paren_count: raise RuntimeError("wut?") paren_count = new_paren_count # Split on parens reaching 0. if 0 >= paren_count: if 0 > first_paren_index: raise RuntimeError("paren inconsistency") return token_tree_split_paren(lst, first_paren_index, ii) elif (1 == paren_count) and (0 > first_paren_index): first_paren_index = ii # Curly braces impossible. else: raise RuntimeError("unknown paren object '%s'" % (str(vv))) # If we're not within parens, consider operators. if is_glsl_operator(vv) and (0 >= bracket_count) and (0 >= paren_count): if (not lowest_operator) or (vv < lowest_operator): lowest_operator = vv lowest_operator_index = ii # Iteration done. Make a tiny subtree on the lowest operator position and continue. if lowest_operator: ret = GlslToken(lowest_operator) left_block = [] right_block = [] left = None right = None # Get extending list left and right. if lowest_operator_index >= 2: left_block = lst[:(lowest_operator_index - 1)] if lowest_operator_index <= len(lst) - 3: right_block = lst[(lowest_operator_index + 2):] # Check for left existing. if lowest_operator_index >= 1: left = lst[lowest_operator_index - 1] ret.addLeft(left) elif not (lowest_operator in ("-", "++", "--", "!")): raise RuntimeError("left component nonexistent for operator '%s'" % (str(lowest_operator))) # Check for right existing. if lowest_operator_index <= len(lst) - 2: right = lst[lowest_operator_index + 1] ret.addRight(right) elif not (lowest_operator in ("++", "--")): raise RuntimeError( "right component nonexistent for operator '%s'" % (str(lowest_operator))) return token_tree_build(left_block + [ret] + right_block) # Only option at this point is that the list has no operators and no parens - return as itself. return GlslToken(lst)
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 token_tree_build(lst): """Builds and balances a token tree from given list.""" # Ensure all list elements are tokens. lst = token_list_create(lst) # Might be that everything is lost at this point. if not lst: return None # Start iteration over tokenized list. bracket_count = 0 paren_count = 0 first_bracket_index = -1 first_paren_index = -1 lowest_operator = None lowest_operator_index = -1 for ii in range(len(lst)): vv = lst[ii].getSingleChild() # Count parens. if is_glsl_paren(vv): # Bracket case. if vv.isBracket(): new_bracket_count = vv.updateBracket(bracket_count) if new_bracket_count == bracket_count: raise RuntimeError("wut?") bracket_count = new_bracket_count # Split on brackets reaching 0. if 0 >= bracket_count: if 0 > first_bracket_index: raise RuntimeError("bracket inconsistency") return token_tree_split_paren(lst, first_bracket_index, ii) elif (1 == bracket_count) and (0 > first_bracket_index): first_bracket_index = ii # Paren case. elif vv.isParen(): new_paren_count = vv.updateParen(paren_count) if new_paren_count == paren_count: raise RuntimeError("wut?") paren_count = new_paren_count # Split on parens reaching 0. if 0 >= paren_count: if 0 > first_paren_index: raise RuntimeError("paren inconsistency") return token_tree_split_paren(lst, first_paren_index, ii) elif (1 == paren_count) and (0 > first_paren_index): first_paren_index = ii # Curly braces impossible. else: raise RuntimeError("unknown paren object '%s'" % (str(vv))) # If we're not within parens, consider operators. if is_glsl_operator(vv) and (0 >= bracket_count) and (0 >= paren_count): if (not lowest_operator) or (vv < lowest_operator): lowest_operator = vv lowest_operator_index = ii # Iteration done. Make a tiny subtree on the lowest operator position and continue. if lowest_operator: ret = GlslToken(lowest_operator) left_block = [] right_block = [] left = None right = None # Get extending list left and right. if lowest_operator_index >= 2: left_block = lst[:(lowest_operator_index - 1)] if lowest_operator_index <= len(lst) - 3: right_block = lst[(lowest_operator_index + 2):] # Check for left existing. if lowest_operator_index >= 1: left = lst[lowest_operator_index - 1] ret.addLeft(left) elif not (lowest_operator in ("-", "++", "--", "!")): raise RuntimeError("left component nonexistent for operator '%s'" % (str(lowest_operator))) # Check for right existing. if lowest_operator_index <= len(lst) - 2: right = lst[lowest_operator_index + 1] ret.addRight(right) elif not (lowest_operator in ("++", "--")): raise RuntimeError("right component nonexistent for operator '%s'" % (str(lowest_operator))) return token_tree_build(left_block + [ret] + right_block) # Only option at this point is that the list has no operators and no parens - return as itself. return GlslToken(lst)
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