コード例 #1
0
ファイル: Operation.py プロジェクト: isabella232/jasy
def compute(node, first=None, second=None, operator=None, session=None):
    """
    Recursively processes given operation node.

    Consumes optional hints for the first/second child of an operation as well as the operator itself (in cases where it
    could not be figured out automatically). The session is useful for supporting commands inside of operations.

    """

    # Fill gaps in empty arguments
    if operator is None:
        operator = node.type

    # Fill missing first/second param
    if first is None and len(node) >= 1:
        first = node[0]

    if second is None and len(node) >= 2:
        second = node[1]

    # Error handling
    if node is None or operator is None:
        raise OperationError("Missing arguments for operation compute()", node)

    # Solve inner operations first
    if first is not None:
        if first.type in Util.ALL_OPERATORS:
            first = compute(first, session=session)
        elif first.type == "command":
            first = Util.executeCommand(first, session)

    if second is not None:
        if second.type in Util.ALL_OPERATORS:
            second = compute(second, session=session)
        elif second.type == "command":
            second = Util.executeCommand(second, session)

    # Support for not-/and-/or-operator
    if operator == "not":
        return Util.castNativeToNode(not castToBool(first))
    elif operator == "and":
        return Util.castNativeToNode(castToBool(first) and castToBool(second))
    elif operator == "or":
        return Util.castNativeToNode(castToBool(first) or castToBool(second))

    # Support for default set operator "?=" when variable was not defined before
    elif operator == "questionmark" and first is None:
        return second


    # Ignore when not yet processed
    if first.type in ("command", "variable") or second.type in ("command", "variable"):
        return

    # Compare operation types
    elif first.type == second.type:
        if first.type in ("true", "false", "null"):
            if operator in ("eq", "ge", "le"):
                return Util.castNativeToNode(True)
            else:
                return Util.castNativeToNode(False)

        elif first.type == "number":
            firstUnit = getattr(first, "unit", None)
            secondUnit = getattr(second, "unit", None)

            if operator in Util.COMPARE_OPERATORS:
                if firstUnit == secondUnit or firstUnit is None or secondUnit is None:
                    if operator == "eq":
                        return Util.castNativeToNode(first.value == second.value)
                    elif operator == "ne":
                        return Util.castNativeToNode(first.value != second.value)
                    elif operator == "gt":
                        return Util.castNativeToNode(first.value > second.value)
                    elif operator == "lt":
                        return Util.castNativeToNode(first.value < second.value)
                    elif operator == "ge":
                        return Util.castNativeToNode(first.value >= second.value)
                    elif operator == "le":
                        return Util.castNativeToNode(first.value <= second.value)

                else:
                    raise OperationError("Unsupported unit combination for number comparison", node)


            elif firstUnit == secondUnit or firstUnit is None or secondUnit is None:
                if operator in Util.MATH_OPERATORS:
                    repl = Node.Node(type="number")

                    if firstUnit is not None:
                        repl.unit = firstUnit
                    elif secondUnit is not None:
                        repl.unit = secondUnit

                    if operator == "plus":
                        repl.value = first.value + second.value
                    elif operator == "minus":
                        repl.value = first.value - second.value
                    elif operator == "mul":
                        repl.value = first.value * second.value
                    elif operator == "div":
                        repl.value = first.value / second.value
                    elif operator == "mod":
                        repl.value = first.value % second.value

                    return repl

                elif operator == "questionmark":
                    return first

                else:
                    raise OperationError("Unsupported number operation", node)


            elif firstUnit == "%" or secondUnit == "%":

                if operator in ("mul", "div"):
                    repl = Node.Node(type="number")

                    if operator == "mul":
                        repl.value = first.value * second.value / 100
                    elif operator == "mul":
                        repl.value = first.value / second.value / 100

                    if firstUnit == "%":
                        repl.unit = secondUnit
                    else:
                        repl.unit = firstUnit

                    return repl

                else:
                    raise OperationError("Could not compute mixed percent operations for operators other than \"*\" and \"/\"", node)

            else:
                raise OperationError("Could not compute result from numbers of different units: %s vs %s" % (first.unit, second.unit), node)


        elif first.type == "string":
            if operator == "plus":
                repl = Node.Node(type="string")
                repl.value = first.value + second.value
                return repl

            elif operator == "eq":
                return Util.castNativeToNode(first.value == second.value)
            elif operator == "ne":
                return Util.castNativeToNode(first.value != second.value)
            else:
                raise OperationError("Unsupported string operation", node)


        elif first.type == "list":
            if len(first) == len(second):
                repl = Node.Node(type="list")
                for pos, child in enumerate(first):
                    childRepl = compute(node, first=child, second=second[pos], session=session)
                    if childRepl is not None:
                        repl.append(childRepl)

                return repl

            else:
                raise OperationError("For list operations both lists have to have the same length!", node)


        else:
            raise OperationError("Unsupported operation on %s" % first.type, node)


    elif first.type == "true" and second.type == "false":
        return Util.castNativeToNode(False)


    elif first.type == "false" and second.type == "true":
        return Util.castNativeToNode(False)


    elif first.type == "list" and second.type != "list":
        repl = Node.Node(type="list")
        for child in first:
            childRepl = compute(node, first=child, second=second, session=session)
            if childRepl is not None:
                repl.append(childRepl)

        return repl


    elif first.type != "list" and second.type == "list":
        repl = Node.Node(type="list")
        for child in second:
            childRepl = compute(node, first=first, second=child, session=session)
            if childRepl is not None:
                repl.append(childRepl)

        return repl


    elif first.type == "string" or second.type == "string":
        repl = Node.Node(type="string")

        if first.type == "identifier" or second.type == "identifier":
            if operator == "plus":
                repl.value = first.value + second.value
                return repl
            elif operator == "eq":
                return Util.castNativeToNode(first.value == second.value)
            elif operator == "ne":
                return Util.castNativeToNode(first.value != second.value)

            else:
                raise OperationError("Unsupported string/identifier operation", node)

        else:

            if operator == "plus":
                repl.value = str(first.value) + str(second.value)
                return repl
            else:
                raise OperationError("Unsupported string operation", node)


    # Just handle when not both are null - equal condition is already done before
    elif first.type == "null" or second.type == "null":
        if operator == "eq":
            return Util.castNativeToNode(False)
        elif operator == "ne":
            return Util.castNativeToNode(True)
        elif operator in Util.MATH_OPERATORS:
            return Util.castNativeToNode(None)
        else:
            raise OperationError("Unsupported operation on null type", node)


    else:
        raise OperationError("Different types in operation: %s vs %s" % (first.type, second.type), node)
コード例 #2
0
ファイル: Executer.py プロジェクト: isabella232/jasy
def __recurser(node, scope, values, profile):
    # Replace variable with actual value
    if node.type == "variable" and not (node.parent.type == "assign"
                                        and node.parent[0] is node):
        name = node.name
        if name not in values:
            raise ExecuterError(
                "Could not resolve variable %s! Missing value!" % name, node)

        value = values[name]
        if value is None:
            raise ExecuterError(
                "Could not resolve variable %s! Value is none!" % name, node)

        Console.debug("Resolving variable: %s at line %s with %s from %s",
                      name, node.line, values[name].type, values[name].line)
        node.parent.replace(node, copy.deepcopy(values[name]))

    # Decide which sub tree of an if-condition is relevant based on current variable situation
    elif node.type == "if":

        Console.debug("Processing if-condition at %s", node.line)

        # Pre-process condition
        # We manually process each child in for if-types
        __recurser(node.condition, scope, values, profile)

        # Cast condition to Python boolean type
        resultValue = Operation.castToBool(node.condition)

        # Process relevant part of the sub tree
        if resultValue is True:
            # Fix missing processing of result node
            __recurser(node.thenPart, scope, values, profile)

            # Finally replace if-node with result node
            node.parent.replace(node, node.thenPart)

        elif resultValue is False and hasattr(node, "elsePart"):
            # Fix missing processing of result node
            __recurser(node.elsePart, scope, values, profile)

            # Finally replace if-node with result node
            node.parent.replace(node, node.elsePart)

        else:
            # Cleanup original if-node
            node.parent.remove(node)

        # Nothing to do here as content is already processed
        return

    # Update scope of new block starts
    if hasattr(node, "scope"):
        relation = getattr(node, "rel", None)

        # Conditional blocks are not exactly blocks in this variable resolution engine
        if not relation in ("thenPart", "elsePart"):
            scope = node.scope
            values = copy.copy(values)
            node.values = values

            # Reset all local variables to None
            # which enforces not to keep values from outer scope
            for name in scope.modified:
                values[name] = None

    # Process children / content
    for child in list(node):
        # Ignore non-children... through possible interactive structure changes
        if child and child.parent is node:
            __recurser(child, scope, values, profile)

    # Update values of variables
    # This happens after processing children to possibly reduce child structure to an easy to assign (aka preprocessed value)
    if (node.type == "declaration"
            and hasattr(node, "initializer")) or node.type == "assign":

        if node.type == "declaration":
            name = node.name
            init = node.initializer
            Console.debug("Found declaration of %s at line %s", name,
                          node.line)

        else:
            name = node[0].name
            init = node[1]
            Console.debug("Found assignment of %s at line %s", name, node.line)

        # Modify value instead of replace when assign operator is set
        if hasattr(node, "assignOp") and node.assignOp is not None:
            if name not in values:
                raise ExecuterError(
                    "Assign operator is not supported as left hand variable is missing: %s"
                    % name, node)

            repl = Operation.compute(node, values[name], init, node.assignOp)
            if repl is not None:
                values[name] = repl

        else:
            # Update internal variable mapping
            # Console.debug("Update value of %s to %s" % (name, init))
            values[name] = init

        # Remove declaration node from tree
        node.parent.remove(node)

    # Support for variables inside property names or selectors
    elif node.type in ("property", "selector") and getattr(
            node, "dynamic", False):

        def replacer(matchObj):
            name = matchObj.group(1)

            if name not in values:
                raise ExecuterError(
                    "Could not resolve variable %s! Missing value!" % name,
                    node)

            value = values[name]
            if value is None:
                raise ExecuterError(
                    "Could not resolve variable %s! Value is none!" % name,
                    node)

            if value.type == "identifier":
                return value.value
            elif value.type == "string":
                return value.value
            elif value.type == "number":
                return "%s%s" % (value.value, getattr(value, "unit", ""))
            else:
                raise ExecuterError(
                    "Could not replace property inline variable with value of type: %s"
                    % value.type, node)

        # Fix all selectors
        if node.type == "selector":
            selectors = node.name
            for pos, selector in enumerate(selectors):
                selectors[pos] = RE_INLINE_VARIABLE.sub(replacer, selector)

        else:
            node.name = RE_INLINE_VARIABLE.sub(replacer, node.name)

    # Execute system commands
    elif node.type == "command":
        repl = Util.executeCommand(node, profile)
        if not repl is node:
            node.parent.replace(node, repl)

    # Support typical operators
    elif node.type in Util.ALL_OPERATORS:
        repl = Operation.compute(node)
        if repl is not None:
            node.parent.replace(node, repl)