Пример #1
0
    def _parse_actions(self, actions):
        """
        Analyze the given list of actions and extract pre/post actions, i.e.
        actions executed before and after handling children.

        :rtype: (list[EnvAction], list[EnvAction])
        """
        actions = list(actions)

        # If present, allow Do actions to come before SetInitialEnv
        self.pre_initial_env_actions = []
        if any(isinstance(a, SetInitialEnv) for a in actions):
            while actions and isinstance(actions[0], Do):
                self.pre_initial_env_actions.append(actions.pop(0))

        # After that, allow one call to SetInitialEnv
        self.initial_env = None
        if actions and isinstance(actions[0], SetInitialEnv):
            self.initial_env = actions.pop(0)

        pre, post = lsplit_by(
            lambda a: not isinstance(a, HandleChildren), actions
        )

        # Get rid of the HandleChildren delimiter action
        post = post and post[1:]

        self.pre_actions = pre
        self.post_actions = post
        self.actions = self.pre_actions + self.post_actions
Пример #2
0
    def _parse_actions(self, actions: List[EnvAction]) -> None:
        """
        Analyze the given list of actions and extract pre/post actions, i.e.
        actions executed before and after handling children.
        """
        def count(cls: Type[EnvAction], sequence: List[EnvAction]) -> int:
            """
            Return the number of ``cls`` instances in ``sequence``.
            """
            return len([a for a in sequence if isinstance(a, cls)])

        # If present, allow Do actions to come before SetInitialEnv
        first_actions = []
        if any(isinstance(a, SetInitialEnv) for a in actions):
            while actions and isinstance(actions[0], Do):
                first_actions.append(actions.pop(0))

        # After that, allow at most one call to SetInitialEnv
        self.initial_env = None
        if actions and isinstance(actions[0], SetInitialEnv):
            check_source_language(
                isinstance(actions[0], SetInitialEnv),
                'The initial environment must come first after the potential'
                ' do()'
            )
            self.initial_env = cast(SetInitialEnv, actions.pop(0))
            first_actions.append(self.initial_env)
        check_source_language(
            count(SetInitialEnv, actions) == 0,
            "set_initial_env can only be preceded by do()"
        )

        check_source_language(
            count(AddEnv, actions) <= 1,
            "There can be at most one call to add_env()"
        )

        # Separate actions that must occur before and after the handling of
        # children. Get also rid of the HandleChildren delimiter action.
        pre, post = lsplit_by(lambda a: not isinstance(a, HandleChildren),
                              actions)
        post = post and post[1:]

        check_source_language(
            count(AddEnv, post) == 0,
            'add_env() must occur before processing children'
        )

        self.pre_actions = first_actions + pre
        self.post_actions = post
        self.actions = self.pre_actions + self.post_actions
Пример #3
0
    def construct(self):
        check_multiple([
            (self.pred_property.type.matches(T.Bool),
             'Predicate property must return a boolean, got {}'.format(
                 self.pred_property.type.dsl_name)),
            (self.pred_property.struct.matches(T.root_node),
             'Predicate property must belong to a subtype of {}'.format(
                 T.root_node.dsl_name)),
        ])

        # Separate logic variable expressions from extra argument expressions
        exprs = [construct(e) for e in self.exprs]
        logic_var_exprs, closure_exprs = funcy.lsplit_by(
            lambda e: e.type == T.LogicVar, exprs)
        check_source_language(
            len(logic_var_exprs) > 0, "Predicate instantiation should have at "
            "least one logic variable expression")
        check_source_language(
            all(e.type != T.LogicVar for e in closure_exprs),
            'Logic variable expressions should be grouped at the beginning,'
            ' and should not appear after non logic variable expressions')

        # Make sure this predicate will work on clean logic variables
        logic_var_exprs = [ResetLogicVar(expr) for expr in logic_var_exprs]

        # Compute the list of arguments to pass to the property (Self
        # included).
        args = (
            [Argument(names.Name('Self'), self.pred_property.struct.entity)] +
            self.pred_property.natural_arguments)

        # Then check that 1) all extra passed actuals match what the property
        # arguments expect and that 2) arguments left without an actual have a
        # default value.
        default_passed_args = 0
        for i, (expr, arg) in enumerate(zip_longest(exprs, args)):

            if expr is None:
                check_source_language(
                    arg.default_value is not None,
                    'Missing an actual for argument #{} ({})'.format(
                        i, arg.name.lower))
                default_passed_args += 1
                continue

            check_source_language(
                arg is not None,
                'Too many actuals: at most {} expected, got {}'.format(
                    len(args), len(exprs)))

            if expr.type == T.LogicVar:
                check_source_language(
                    arg.type.matches(T.root_node.entity),
                    "Argument #{} of predicate "
                    "is a logic variable, the corresponding property formal "
                    "has type {}, but should be a descendent of {}".format(
                        i, arg.type.dsl_name, T.root_node.entity.dsl_name))
            else:
                check_source_language(
                    expr.type.matches(arg.type), "Argument #{} of predicate "
                    "has type {}, should be {}".format(i, expr.type.dsl_name,
                                                       arg.type.dsl_name))

        DynamicVariable.check_call_bindings(self.pred_property,
                                            'In predicate property {prop}')

        # Append dynamic variables to embed their values in the closure
        closure_exprs.extend(
            construct(dynvar) for dynvar in self.pred_property.dynamic_vars)

        pred_id = self.pred_property.do_generate_logic_predicate(
            tuple(e.type for e in closure_exprs), default_passed_args)

        args = " ({})".format(', '.join(
            ["{}"
             for _ in range(len(closure_exprs))])) if closure_exprs else ""
        predicate_expr = untyped_literal_expr(
            f"Create_{pred_id}_Predicate{args}", operands=closure_exprs)

        return Predicate.Expr(self.pred_property,
                              pred_id,
                              logic_var_exprs,
                              predicate_expr,
                              abstract_expr=self)