示例#1
0
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)
示例#2
0
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)
示例#3
0
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)
示例#4
0
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)
示例#5
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")
示例#6
0
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
示例#7
0
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)
示例#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
示例#9
0
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)
示例#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