Esempio n. 1
0
def gather_used_variables(model, variables, rewrite_table):
    """Gather the variables that are used within the statements"""
    class_name = model.__class__.__name__
    if class_name in ["Assignment", "Expression", "ExprPrec1", "ExprPrec2", "ExprPrec3", "ExprPrec4"]:
        gather_used_variables(model.left, variables, rewrite_table)
        if model.right is not None:
            gather_used_variables(model.right, variables, rewrite_table)
    elif class_name == "ExpressionRef":
        if model.index is None:
            variables.update({(model.ref, None)})
        else:
            # The index might hide a variable within it.
            variables.update({(model.ref, get_instruction(model.index, rewrite_table))})
            gather_used_variables(model.index, variables, rewrite_table)
    elif class_name == "VariableRef":
        if model.index is None:
            variables.update({(model.var.name, None)})
        else:
            # The index might hide a variable within it.
            variables.update({(model.var.name, get_instruction(model.index, rewrite_table))})
            gather_used_variables(model.index, variables, rewrite_table)
    elif class_name == "Primary" and model.ref is not None:
        return gather_used_variables(model.ref, variables, rewrite_table)
    else:
        return set([])
Esempio n. 2
0
def annotate_used_variables(o, global_variables, rewrite_table=None):
    """Add the used variables to Composites, Expressions and Assignments.
       The rewrite table is used to compensate for variable changes in composite statements."""
    class_name = o.__class__.__name__
    if class_name == "Class":
        for sm in o.statemachines:
            annotate_used_variables(sm, global_variables, rewrite_table)
    if class_name == "StateMachine":
        for transition in o.transitions:
            annotate_used_variables(transition, global_variables, rewrite_table)
    elif class_name == "Transition":
        o.variables = set([])
        o.lock_requests = set([])
        for statement in o.statements:
            annotate_used_variables(statement, global_variables, rewrite_table)
            o.variables.update(statement.variables)
            o.lock_requests.update(statement.lock_requests)
    elif class_name == "Composite":
        o.variables = set([])
        o.lock_requests = set([])
        rewrite_table = {}

        # Annotate the guard variable first.
        annotate_used_variables(o.guard, global_variables, rewrite_table)
        o.variables.update(o.guard.variables)
        o.lock_requests.update(o.guard.lock_requests)

        # Annotate the assignments and update the rewrite table.
        for assignment in o.assignments:
            annotate_used_variables(assignment, global_variables, rewrite_table)
            o.variables.update(assignment.variables)
            o.lock_requests.update(assignment.lock_requests)

            # Add a rewrite rule, changing the left-hand side into the right-hand side.
            # Note that in the left hand side, we only rewrite the index, if available.
            target_variable = assignment.left.var.name
            if assignment.left.index is not None:
                target_variable += "[" + get_instruction(assignment.left.index, rewrite_table) + "]"
            target_rewrite = get_instruction(assignment.right, rewrite_table)

            if ' ' in target_rewrite:
                rewrite_table[target_variable] = "(%s)" % target_rewrite
            else:
                rewrite_table[target_variable] = "%s" % target_rewrite
    elif class_name in ["Expression", "Assignment"]:
        o.variables = set([])
        gather_used_variables(o, o.variables, rewrite_table)
        o.lock_requests = set([(name, sub) for name, sub in o.variables if name in global_variables])
Esempio n. 3
0
def annotate_statement(s):
    """Transform the statement such that it provides all the data required for the code conversion"""
    class_name = s.__class__.__name__
    if class_name == "Composite":
        # Always make sure that a guard expression exists, defaulting to a "True" expression.
        s.guard = get_true_expression() if s.guard is None else annotate_statement(s.guard)
        s.assignments = [annotate_statement(a) for a in s.assignments]
    elif class_name == "Expression":
        s.string_expression = get_instruction(s)
        # Provide equality and hash functions such that the expressions can be added to a set.
        s.__eq__ = lambda self, other: self.string_expression == other.string_expression
        s.__hash__ = lambda self: hash(self.__repr__())

    # Give all statements a readable string representation corresponding to the associated java code.
    s.__repr__ = lambda self: get_instruction(self)

    return s
Esempio n. 4
0
def get_true_expression():
    """An expression that represents an object that is always true, used as replacement for empty guards"""
    return type("Expression", (object,), {
        "left": type("Primary", (object,), {"value": True, "sign": "", "body": None, "ref": None})(),
        "op": "",
        "right": None,
        "string_expression": "true",
        "is_trivially_satisfiable": True,
        "is_trivially_unsatisfiable": False,
        "lock_requests": set([]),
        "__repr__": lambda self: get_instruction(self),
    })()
Esempio n. 5
0
def get_guard_statement(model):
    """Construct an or-code-clause encapsulating all guard expressions for the target decision block"""
    if model.__class__.__name__ == "TransitionBlock":
        return get_instruction(model.guard_expression)
    else:
        # Remove statements that have the same solution space.
        duplicate_expressions = set([])
        for e_1 in model.guard_expressions:
            for e_2 in model.guard_expressions:
                if e_1 == e_2:
                    break
                if z3_check_equality(e_1.z3py_expression, e_2.z3py_expression,
                                     True):
                    duplicate_expressions.add(e_1)
        guard_expressions = [
            e for e in model.guard_expressions
            if e not in duplicate_expressions
        ]

        # Check if expressions are superfluous, i.e., contained within another statement.
        implies_truth_matrix = {}
        for e_1 in guard_expressions:
            implies_truth_matrix[e_1] = {}
            for e_2 in guard_expressions:
                if e_1 == e_2:
                    implies_truth_matrix[e_1][e_2] = False
                else:
                    implies_truth_matrix[e_1][e_2] = z3_check_implies(
                        e_1.z3py_expression, e_2.z3py_expression, True)

        # If any of the values is true, remove the guard expression from the result, since it is included in another.
        target_expressions = []
        for e_1 in guard_expressions:
            if e_1 not in duplicate_expressions and not any(
                    implies_truth_matrix[e_1].values()):
                target_expressions.append(e_1)

        # Construct a disjunction of statements. Brackets are not needed because of the precedence order.
        return " || ".join([get_instruction(e) for e in target_expressions])
Esempio n. 6
0
def construct_decision_code(model, sm, no_current_state):
    """Convert the decision structure to Java code"""
    model_class = model.__class__.__name__
    if model_class == "TransitionBlock":
        statements = [
            construct_decision_code(s, sm, no_current_state)
            for s in model.statements
        ]
        statements = [s for s in statements if s != ""]
        return java_transition_template.render(
            statements=statements,
            target=model.target,
            state_machine_name=sm.name,
            always_fails=model.always_fails,
            comment=model.comment,
            add_performance_counters=settings.add_performance_counter,
            render_current_state_variable=no_current_state)
    elif model_class == "CompositeBlock":
        return java_composite_template.render(model=model, _c=sm.parent_class)
    elif model_class == "AssignmentBlock":
        return java_assignment_template.render(model=model, _c=sm.parent_class)
    elif model_class == "ExpressionBlock":
        return java_expression_template.render(model=model, _c=sm.parent_class)
    elif model_class == "ActionRef":
        return "// Execute action [%s]\n" % model.act.name
    elif model_class == "NonDeterministicBlock":
        # Several of the choices may have the same conversion string. Filter these out and merge.
        choices = [
            construct_decision_code(choice, sm, no_current_state)
            for choice in model.choice_blocks
        ]
        choices.sort(key=lambda v: v[0])

        # If only one choice remains, there is no reason to include an entire block.
        if len(choices) == 1:
            return choices[0]

        return java_pick_randomly_template.render(choices=choices,
                                                  _c=sm.parent_class)
    elif model_class == "DeterministicIfThenElseBlock":
        # Order the choices such that the generated code is always the same.
        choices = [(construct_decision_code(choice, sm, no_current_state),
                    get_guard_statement(choice))
                   for choice in model.choice_blocks]
        choices.sort(key=lambda v: v[0])

        # Does the combination of all the guards always evaluate to true?
        else_choice = None
        if model.close_with_else:
            else_choice = choices[-1]
            choices = choices[:-1]

        return java_if_then_else_template.render(choices=choices,
                                                 else_choice=else_choice,
                                                 model=model,
                                                 _c=sm.parent_class)
    elif model_class == "DeterministicCaseDistinctionBlock":
        # Several of the choices may have the same conversion string. Filter these out and merge.
        choices = [
            (target, construct_decision_code(choice, sm,
                                             no_current_state), choice.comment
             if choice.__class__.__name__ == "TransitionBlock" else None)
            for (target, choice) in model.choice_blocks
        ]
        choices.sort(key=lambda v: v[1])

        subject_expression = get_instruction(model.subject_expression)
        default_decision_tree = construct_decision_code(
            model.default_decision_tree, sm, no_current_state)
        return java_case_distinction_template.render(
            subject_expression=subject_expression,
            default_decision_tree=default_decision_tree,
            choices=choices,
            model=model,
            _c=sm.parent_class)