roby 0.8.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.deep-cover.rb +3 -0
- data/.gitattributes +1 -0
- data/.gitignore +24 -0
- data/.simplecov +10 -0
- data/.travis.yml +17 -0
- data/.yardopts +4 -0
- data/Gemfile +15 -0
- data/README.md +11 -0
- data/Rakefile +47 -177
- data/benchmark/{alloc_misc.rb → attic/alloc_misc.rb} +2 -2
- data/benchmark/{discovery_latency.rb → attic/discovery_latency.rb} +19 -19
- data/benchmark/{garbage_collection.rb → attic/garbage_collection.rb} +9 -9
- data/benchmark/{genom.rb → attic/genom.rb} +0 -0
- data/benchmark/attic/transactions.rb +62 -0
- data/benchmark/plan_basic_operations.rb +28 -0
- data/benchmark/relations/graph.rb +63 -0
- data/benchmark/ruby/identity.rb +18 -0
- data/benchmark/ruby/set_intersect_vs_hash_merge.rb +39 -0
- data/benchmark/ruby/yield_vs_block.rb +35 -0
- data/benchmark/run +5 -0
- data/benchmark/synthetic_plan_modifications_with_transactions.rb +79 -0
- data/benchmark/transactions.rb +99 -51
- data/bin/roby +38 -197
- data/bin/roby-display +14 -0
- data/bin/roby-log +3 -176
- data/doc/guide/{src → attic}/abstraction/achieve_with.page +1 -1
- data/doc/guide/{src → attic}/abstraction/forwarding.page +1 -1
- data/doc/guide/{src → attic}/abstraction/hierarchy.page +1 -1
- data/doc/guide/{src → attic}/abstraction/index.page +1 -1
- data/doc/guide/{src → attic}/abstraction/task_models.page +1 -1
- data/doc/guide/{overview.rdoc → attic/cycle/api_overview.rdoc} +6 -1
- data/doc/guide/{src → attic}/cycle/cycle-overview.png +0 -0
- data/doc/guide/{src → attic}/cycle/cycle-overview.svg +0 -0
- data/doc/guide/attic/cycle/error_handling.page +98 -0
- data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.png +0 -0
- data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.svg +0 -0
- data/doc/guide/{src/cycle/error_handling.page → attic/cycle/error_sources.page} +46 -89
- data/doc/guide/{src → attic}/cycle/garbage_collection.page +1 -1
- data/doc/guide/{src → attic}/cycle/index.page +1 -1
- data/doc/guide/{src → attic}/cycle/propagation.page +11 -1
- data/doc/guide/{src → attic}/cycle/propagation_diamond.png +0 -0
- data/doc/guide/{src → attic}/cycle/propagation_diamond.svg +0 -0
- data/doc/guide/attic/plans/building_plans.page +89 -0
- data/doc/guide/attic/plans/code.page +192 -0
- data/doc/guide/{src/basics → attic/plans}/events.page +3 -4
- data/doc/guide/attic/plans/index.page +7 -0
- data/doc/guide/{plan_modifications.rdoc → attic/plans/plan_modifications.rdoc} +5 -3
- data/doc/guide/{src/basics → attic/plans}/plan_objects.page +2 -1
- data/doc/guide/attic/plans/querying_plans.page +5 -0
- data/doc/guide/{src/basics → attic/plans}/tasks.page +20 -20
- data/doc/guide/config.yaml +7 -4
- data/doc/guide/ext/extended_menu.rb +29 -0
- data/doc/guide/ext/init.rb +6 -0
- data/doc/guide/ext/rdoc_links.rb +7 -6
- data/doc/guide/src/advanced_concepts/history.page +5 -0
- data/doc/guide/src/advanced_concepts/index.page +11 -0
- data/doc/guide/src/advanced_concepts/recognizing_patterns.page +83 -0
- data/doc/guide/src/advanced_concepts/scheduling.page +87 -0
- data/doc/guide/src/advanced_concepts/transactions.page +5 -0
- data/doc/guide/src/advanced_concepts/unreachability.page +42 -0
- data/doc/guide/src/base.template +96 -0
- data/doc/guide/src/basics_shell_header.txt +5 -7
- data/doc/guide/src/building/action_coordination.page +96 -0
- data/doc/guide/src/building/actions.page +124 -0
- data/doc/guide/src/building/file_layout.page +71 -0
- data/doc/guide/src/building/index.page +50 -0
- data/doc/guide/src/building/patterns.page +86 -0
- data/doc/guide/src/building/patterns_forwarding.png +0 -0
- data/doc/guide/src/building/patterns_forwarding.svg +277 -0
- data/doc/guide/src/building/runtime.page +95 -0
- data/doc/guide/src/building/task_models.page +94 -0
- data/doc/guide/src/building/tasks.page +284 -0
- data/doc/guide/src/concepts/error_handling.page +100 -0
- data/doc/guide/src/concepts/exception_propagation.png +0 -0
- data/doc/guide/src/concepts/exception_propagation.svg +445 -0
- data/doc/guide/src/concepts/execution.page +85 -0
- data/doc/guide/src/concepts/execution.png +0 -0
- data/doc/guide/src/concepts/execution.svg +573 -0
- data/doc/guide/src/concepts/execution_cycle.png +0 -0
- data/doc/guide/src/concepts/garbage_collection.page +57 -0
- data/doc/guide/src/concepts/index.page +27 -0
- data/doc/guide/src/concepts/plans.page +101 -0
- data/doc/guide/src/concepts/policy.page +31 -0
- data/doc/guide/src/concepts/reactor.page +61 -0
- data/doc/guide/src/concepts/simple_plan_example.png +0 -0
- data/doc/guide/src/concepts/simple_plan_example.svg +376 -0
- data/doc/guide/src/default.template +9 -74
- data/doc/guide/src/event_relations/forward.page +71 -0
- data/doc/guide/src/event_relations/index.page +12 -0
- data/doc/guide/src/event_relations/scheduling_constraints.page +43 -0
- data/doc/guide/src/event_relations/signal.page +55 -0
- data/doc/guide/src/event_relations/temporal_constraints.page +77 -0
- data/doc/guide/src/htmldoc.metainfo +21 -8
- data/doc/guide/src/index.page +8 -3
- data/doc/guide/src/{introduction/install.page → installation/index.page} +37 -25
- data/doc/guide/src/installation/publications.page +14 -0
- data/doc/guide/src/{introduction → installation}/videos.page +14 -7
- data/doc/guide/src/interacting/index.page +16 -0
- data/doc/guide/src/interacting/run.page +33 -0
- data/doc/guide/src/interacting/shell.page +95 -0
- data/doc/guide/src/plugins/creating_plugins.page +72 -0
- data/doc/guide/src/plugins/index.page +27 -5
- data/doc/guide/src/plugins/{fault_tolerance.page → standard_plugins/fault_tolerance.page} +2 -2
- data/doc/guide/src/plugins/standard_plugins/index.page +11 -0
- data/doc/guide/src/plugins/{subsystems.page → standard_plugins/subsystems.page} +2 -2
- data/doc/guide/src/style_screen.css +687 -0
- data/doc/guide/src/task_relations/dependency.page +107 -0
- data/doc/guide/src/task_relations/executed_by.page +77 -0
- data/doc/guide/src/task_relations/index.page +12 -0
- data/doc/guide/src/task_relations/new_relations.page +119 -0
- data/doc/guide/src/task_relations/planned_by.page +46 -0
- data/doc/guide/src/tutorial/app.page +117 -0
- data/doc/guide/src/{basics → tutorial}/code_examples.page +6 -5
- data/doc/guide/src/{basics → tutorial}/dry.page +15 -15
- data/doc/guide/src/{basics → tutorial}/errors.page +43 -68
- data/doc/guide/src/tutorial/events.page +195 -0
- data/doc/guide/src/{basics → tutorial}/hierarchy.page +53 -52
- data/doc/guide/src/tutorial/index.page +13 -0
- data/doc/guide/src/tutorial/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/goForward_4.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_1.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_2.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_3.png +0 -0
- data/doc/guide/src/tutorial/log_replay/moveto_code_error.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_1.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_2.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_3.png +0 -0
- data/doc/guide/src/tutorial/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/tutorial/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/roby_log_relation_window.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/roby_replay_event_representation.png +0 -0
- data/doc/guide/src/tutorial/relations_display.page +153 -0
- data/doc/guide/src/{basics → tutorial}/roby_cycle_overview.png +0 -0
- data/doc/guide/src/tutorial/shell.page +121 -0
- data/doc/guide/src/{basics → tutorial}/summary.page +1 -1
- data/doc/guide/src/tutorial/tasks.page +374 -0
- data/lib/roby.rb +102 -47
- data/lib/roby/actions.rb +17 -0
- data/lib/roby/actions/action.rb +80 -0
- data/lib/roby/actions/interface.rb +45 -0
- data/lib/roby/actions/library.rb +23 -0
- data/lib/roby/actions/models/action.rb +224 -0
- data/lib/roby/actions/models/coordination_action.rb +58 -0
- data/lib/roby/actions/models/interface.rb +22 -0
- data/lib/roby/actions/models/interface_base.rb +294 -0
- data/lib/roby/actions/models/library.rb +12 -0
- data/lib/roby/actions/models/method_action.rb +90 -0
- data/lib/roby/actions/task.rb +114 -0
- data/lib/roby/and_generator.rb +125 -0
- data/lib/roby/app.rb +2795 -829
- data/lib/roby/app/autotest_console_reporter.rb +138 -0
- data/lib/roby/app/base.rb +21 -0
- data/lib/roby/app/cucumber.rb +2 -0
- data/lib/roby/app/cucumber/controller.rb +439 -0
- data/lib/roby/app/cucumber/helpers.rb +280 -0
- data/lib/roby/app/cucumber/world.rb +32 -0
- data/lib/roby/app/debug.rb +136 -0
- data/lib/roby/app/gen.rb +2 -0
- data/lib/roby/app/rake.rb +178 -38
- data/lib/roby/app/robot_config.rb +9 -0
- data/lib/roby/app/robot_names.rb +115 -0
- data/lib/roby/app/run.rb +3 -2
- data/lib/roby/app/scripts.rb +72 -0
- data/lib/roby/app/scripts/autotest.rb +173 -0
- data/lib/roby/app/scripts/display.rb +2 -0
- data/lib/roby/app/scripts/restart.rb +52 -0
- data/lib/roby/app/scripts/results.rb +17 -8
- data/lib/roby/app/scripts/run.rb +155 -24
- data/lib/roby/app/scripts/shell.rb +147 -62
- data/lib/roby/app/scripts/test.rb +107 -22
- data/lib/roby/app/test_reporter.rb +74 -0
- data/lib/roby/app/test_server.rb +159 -0
- data/lib/roby/app/vagrant.rb +47 -0
- data/lib/roby/backports.rb +16 -0
- data/lib/roby/cli/display.rb +190 -0
- data/lib/roby/cli/exceptions.rb +17 -0
- data/lib/roby/cli/gen/actions/class.rb +5 -0
- data/lib/roby/cli/gen/actions/test.rb +6 -0
- data/lib/roby/cli/gen/app/.yardopts +6 -0
- data/lib/roby/cli/gen/app/README.md +28 -0
- data/lib/roby/cli/gen/app/Rakefile +15 -0
- data/{app → lib/roby/cli/gen/app}/config/app.yml +29 -39
- data/lib/roby/cli/gen/app/models/.gitattributes +1 -0
- data/{app → lib/roby/cli/gen/app/scripts}/controllers/.gitattributes +0 -0
- data/{app/data/.gitattributes → lib/roby/cli/gen/app/test/.gitignore} +0 -0
- data/lib/roby/cli/gen/class/class.rb +6 -0
- data/lib/roby/cli/gen/class/test.rb +7 -0
- data/lib/roby/cli/gen/helpers.rb +203 -0
- data/lib/roby/cli/gen/module/module.rb +5 -0
- data/lib/roby/cli/gen/module/test.rb +6 -0
- data/lib/roby/cli/gen/roby_app/config/init.rb +17 -0
- data/lib/roby/cli/gen/roby_app/config/robots/robot.rb +40 -0
- data/lib/roby/cli/gen/task/class.rb +44 -0
- data/lib/roby/cli/gen/task/test.rb +6 -0
- data/lib/roby/cli/gen_main.rb +120 -0
- data/lib/roby/cli/log.rb +276 -0
- data/lib/roby/cli/log/flamegraph.html +499 -0
- data/lib/roby/cli/log/flamegraph_renderer.rb +88 -0
- data/lib/roby/cli/main.rb +153 -0
- data/lib/roby/coordination.rb +60 -0
- data/lib/roby/coordination/action_script.rb +25 -0
- data/lib/roby/coordination/action_state_machine.rb +125 -0
- data/lib/roby/coordination/actions.rb +106 -0
- data/lib/roby/coordination/base.rb +145 -0
- data/lib/roby/coordination/calculus.rb +40 -0
- data/lib/roby/coordination/child.rb +28 -0
- data/lib/roby/coordination/event.rb +29 -0
- data/lib/roby/coordination/fault_handler.rb +25 -0
- data/lib/roby/coordination/fault_handling_task.rb +13 -0
- data/lib/roby/coordination/fault_response_table.rb +110 -0
- data/lib/roby/coordination/models/action_script.rb +64 -0
- data/lib/roby/coordination/models/action_state_machine.rb +224 -0
- data/lib/roby/coordination/models/actions.rb +191 -0
- data/lib/roby/coordination/models/arguments.rb +55 -0
- data/lib/roby/coordination/models/base.rb +176 -0
- data/lib/roby/coordination/models/capture.rb +86 -0
- data/lib/roby/coordination/models/child.rb +35 -0
- data/lib/roby/coordination/models/event.rb +41 -0
- data/lib/roby/coordination/models/exceptions.rb +42 -0
- data/lib/roby/coordination/models/fault_handler.rb +219 -0
- data/lib/roby/coordination/models/fault_response_table.rb +77 -0
- data/lib/roby/coordination/models/root.rb +22 -0
- data/lib/roby/coordination/models/script.rb +283 -0
- data/lib/roby/coordination/models/task.rb +184 -0
- data/lib/roby/coordination/models/task_from_action.rb +50 -0
- data/lib/roby/coordination/models/task_from_as_plan.rb +33 -0
- data/lib/roby/coordination/models/task_from_instanciation_object.rb +31 -0
- data/lib/roby/coordination/models/task_from_variable.rb +27 -0
- data/lib/roby/coordination/models/task_with_dependencies.rb +48 -0
- data/lib/roby/coordination/models/variable.rb +32 -0
- data/lib/roby/coordination/script.rb +200 -0
- data/lib/roby/coordination/script_instruction.rb +12 -0
- data/lib/roby/coordination/task.rb +45 -0
- data/lib/roby/coordination/task_base.rb +69 -0
- data/lib/roby/coordination/task_script.rb +293 -0
- data/lib/roby/coordination/task_state_machine.rb +308 -0
- data/lib/roby/decision_control.rb +33 -21
- data/lib/roby/distributed_object.rb +76 -0
- data/lib/roby/droby.rb +17 -0
- data/lib/roby/droby/droby_id.rb +6 -0
- data/lib/roby/droby/enable.rb +153 -0
- data/lib/roby/droby/event_logger.rb +189 -0
- data/lib/roby/droby/event_logging.rb +57 -0
- data/lib/roby/droby/exceptions.rb +14 -0
- data/lib/roby/droby/identifiable.rb +22 -0
- data/lib/roby/droby/logfile.rb +141 -0
- data/lib/roby/droby/logfile/client.rb +176 -0
- data/lib/roby/droby/logfile/file_format.md +97 -0
- data/lib/roby/droby/logfile/index.rb +117 -0
- data/lib/roby/droby/logfile/reader.rb +139 -0
- data/lib/roby/droby/logfile/server.rb +199 -0
- data/lib/roby/droby/logfile/writer.rb +114 -0
- data/lib/roby/droby/marshal.rb +264 -0
- data/lib/roby/droby/marshallable.rb +12 -0
- data/lib/roby/droby/null_event_logger.rb +25 -0
- data/lib/roby/droby/object_manager.rb +205 -0
- data/lib/roby/droby/peer_id.rb +6 -0
- data/lib/roby/droby/plan_rebuilder.rb +373 -0
- data/lib/roby/droby/rebuilt_plan.rb +160 -0
- data/lib/roby/droby/remote_droby_id.rb +6 -0
- data/lib/roby/droby/timepoints.rb +205 -0
- data/lib/roby/droby/timepoints_ctf.metadata.erb +101 -0
- data/lib/roby/droby/timepoints_ctf.rb +125 -0
- data/lib/roby/droby/v5.rb +14 -0
- data/lib/roby/droby/v5/builtin.rb +120 -0
- data/lib/roby/droby/v5/droby_class.rb +45 -0
- data/lib/roby/droby/v5/droby_constant.rb +81 -0
- data/lib/roby/droby/v5/droby_dump.rb +1026 -0
- data/lib/roby/droby/v5/droby_id.rb +44 -0
- data/lib/roby/droby/v5/droby_model.rb +82 -0
- data/lib/roby/droby/v5/peer_id.rb +10 -0
- data/lib/roby/droby/v5/remote_droby_id.rb +42 -0
- data/lib/roby/event.rb +79 -957
- data/lib/roby/event_constraints.rb +835 -0
- data/lib/roby/event_generator.rb +1047 -0
- data/lib/roby/event_structure/causal_link.rb +6 -0
- data/lib/roby/event_structure/forwarding.rb +6 -0
- data/lib/roby/event_structure/precedence.rb +7 -0
- data/lib/roby/event_structure/signal.rb +8 -0
- data/lib/roby/event_structure/temporal_constraints.rb +640 -0
- data/lib/roby/exceptions.rb +446 -152
- data/lib/roby/executable_plan.rb +549 -0
- data/lib/roby/execution_engine.rb +1997 -950
- data/lib/roby/filter_generator.rb +26 -0
- data/lib/roby/gui/chronicle_view.rb +225 -0
- data/lib/roby/gui/chronicle_widget.rb +925 -0
- data/lib/roby/gui/dot_id.rb +11 -0
- data/lib/roby/gui/exception_view.rb +44 -0
- data/lib/roby/gui/log_display.rb +273 -0
- data/lib/roby/gui/model_views.rb +2 -0
- data/lib/roby/gui/model_views/action_interface.rb +53 -0
- data/lib/roby/gui/model_views/task.rb +47 -0
- data/lib/roby/gui/model_views/task.rhtml +41 -0
- data/lib/roby/gui/object_info_view.rb +89 -0
- data/lib/roby/gui/plan_dot_layout.rb +427 -0
- data/lib/roby/gui/plan_rebuilder_widget.rb +357 -0
- data/lib/roby/gui/qt4_toMSecsSinceEpoch.rb +8 -0
- data/lib/roby/gui/relations_view.rb +278 -0
- data/lib/roby/gui/relations_view/relations.ui +139 -0
- data/lib/roby/gui/relations_view/relations_canvas.rb +1088 -0
- data/lib/roby/gui/relations_view/relations_config.rb +292 -0
- data/lib/roby/gui/relations_view/relations_view.ui +53 -0
- data/lib/roby/gui/scheduler_view.css +24 -0
- data/lib/roby/gui/scheduler_view.rb +46 -0
- data/lib/roby/gui/scheduler_view.rhtml +53 -0
- data/lib/roby/gui/stepping.rb +93 -0
- data/lib/roby/gui/stepping.ui +181 -0
- data/lib/roby/gui/styles.rb +81 -0
- data/lib/roby/gui/task_display_configuration.rb +42 -0
- data/lib/roby/gui/task_state_at.rb +38 -0
- data/lib/roby/hooks.rb +26 -0
- data/lib/roby/interface.rb +136 -469
- data/lib/roby/interface/async.rb +20 -0
- data/lib/roby/interface/async/action_monitor.rb +188 -0
- data/lib/roby/interface/async/interface.rb +498 -0
- data/lib/roby/interface/async/job_monitor.rb +213 -0
- data/lib/roby/interface/async/log.rb +238 -0
- data/lib/roby/interface/async/new_job_listener.rb +79 -0
- data/lib/roby/interface/async/ui_connector.rb +183 -0
- data/lib/roby/interface/client.rb +553 -0
- data/lib/roby/interface/command.rb +24 -0
- data/lib/roby/interface/command_argument.rb +16 -0
- data/lib/roby/interface/command_library.rb +92 -0
- data/lib/roby/interface/droby_channel.rb +174 -0
- data/lib/roby/interface/exceptions.rb +22 -0
- data/lib/roby/interface/interface.rb +655 -0
- data/lib/roby/interface/job.rb +47 -0
- data/lib/roby/interface/rest.rb +10 -0
- data/lib/roby/interface/rest/api.rb +29 -0
- data/lib/roby/interface/rest/helpers.rb +24 -0
- data/lib/roby/interface/rest/server.rb +212 -0
- data/lib/roby/interface/server.rb +154 -0
- data/lib/roby/interface/shell_client.rb +468 -0
- data/lib/roby/interface/shell_subcommand.rb +24 -0
- data/lib/roby/interface/subcommand_client.rb +35 -0
- data/lib/roby/interface/tcp.rb +168 -0
- data/lib/roby/models/arguments.rb +112 -0
- data/lib/roby/models/plan_object.rb +83 -0
- data/lib/roby/models/task.rb +835 -0
- data/lib/roby/models/task_event.rb +62 -0
- data/lib/roby/models/task_service.rb +78 -0
- data/lib/roby/or_generator.rb +88 -0
- data/lib/roby/plan.rb +1751 -864
- data/lib/roby/plan_object.rb +611 -0
- data/lib/roby/plan_service.rb +200 -0
- data/lib/roby/promise.rb +332 -0
- data/lib/roby/queries.rb +23 -0
- data/lib/roby/queries/and_matcher.rb +32 -0
- data/lib/roby/queries/any.rb +27 -0
- data/lib/roby/queries/code_error_matcher.rb +58 -0
- data/lib/roby/queries/event_generator_matcher.rb +9 -0
- data/lib/roby/queries/execution_exception_matcher.rb +165 -0
- data/lib/roby/queries/index.rb +165 -0
- data/lib/roby/queries/localized_error_matcher.rb +149 -0
- data/lib/roby/queries/matcher_base.rb +107 -0
- data/lib/roby/queries/none.rb +27 -0
- data/lib/roby/queries/not_matcher.rb +30 -0
- data/lib/roby/queries/op_matcher.rb +8 -0
- data/lib/roby/queries/or_matcher.rb +30 -0
- data/lib/roby/queries/plan_object_matcher.rb +363 -0
- data/lib/roby/queries/query.rb +188 -0
- data/lib/roby/queries/task_event_generator_matcher.rb +86 -0
- data/lib/roby/queries/task_matcher.rb +344 -0
- data/lib/roby/relations.rb +42 -678
- data/lib/roby/relations/bidirectional_directed_adjacency_graph.rb +492 -0
- data/lib/roby/relations/directed_relation_support.rb +268 -0
- data/lib/roby/relations/event_relation_graph.rb +19 -0
- data/lib/roby/relations/fork_merge_visitor.rb +154 -0
- data/lib/roby/relations/graph.rb +533 -0
- data/lib/roby/relations/models/directed_relation_support.rb +11 -0
- data/lib/roby/relations/models/graph.rb +75 -0
- data/lib/roby/relations/models/task_relation_graph.rb +18 -0
- data/lib/roby/relations/space.rb +380 -0
- data/lib/roby/relations/task_relation_graph.rb +20 -0
- data/lib/roby/robot.rb +85 -38
- data/lib/roby/schedulers/basic.rb +155 -25
- data/lib/roby/schedulers/null.rb +20 -0
- data/lib/roby/schedulers/reporting.rb +31 -0
- data/lib/roby/schedulers/state.rb +129 -0
- data/lib/roby/schedulers/temporal.rb +91 -0
- data/lib/roby/singletons.rb +87 -0
- data/lib/roby/standalone.rb +4 -2
- data/lib/roby/standard_errors.rb +405 -82
- data/lib/roby/state.rb +6 -3
- data/lib/roby/state/conf_model.rb +5 -0
- data/lib/roby/state/events.rb +181 -95
- data/lib/roby/state/goal_model.rb +77 -0
- data/lib/roby/state/open_struct.rb +591 -0
- data/lib/roby/state/open_struct_model.rb +68 -0
- data/lib/roby/state/pos.rb +45 -45
- data/lib/roby/state/shapes.rb +11 -11
- data/lib/roby/state/state_model.rb +303 -0
- data/lib/roby/state/task.rb +43 -0
- data/lib/roby/support.rb +88 -148
- data/lib/roby/task.rb +1361 -1750
- data/lib/roby/task_arguments.rb +428 -0
- data/lib/roby/task_event.rb +127 -0
- data/lib/roby/task_event_generator.rb +337 -0
- data/lib/roby/task_service.rb +6 -0
- data/lib/roby/task_structure/conflicts.rb +104 -0
- data/lib/roby/task_structure/dependency.rb +932 -0
- data/lib/roby/task_structure/error_handling.rb +118 -0
- data/lib/roby/task_structure/executed_by.rb +234 -0
- data/lib/roby/task_structure/planned_by.rb +90 -0
- data/lib/roby/tasks/aggregator.rb +37 -0
- data/lib/roby/tasks/external_process.rb +275 -0
- data/lib/roby/tasks/group.rb +27 -0
- data/lib/roby/tasks/null.rb +19 -0
- data/lib/roby/tasks/parallel.rb +43 -0
- data/lib/roby/tasks/sequence.rb +88 -0
- data/lib/roby/tasks/simple.rb +21 -0
- data/lib/roby/{thread_task.rb → tasks/thread.rb} +50 -24
- data/lib/roby/tasks/timeout.rb +17 -0
- data/lib/roby/tasks/virtual.rb +55 -0
- data/lib/roby/template_plan.rb +7 -0
- data/lib/roby/test/aruba_minitest.rb +74 -0
- data/lib/roby/test/assertion.rb +16 -0
- data/lib/roby/test/assertions.rb +490 -0
- data/lib/roby/test/common.rb +368 -591
- data/lib/roby/test/dsl.rb +149 -0
- data/lib/roby/test/error.rb +18 -0
- data/lib/roby/test/event_reporter.rb +83 -0
- data/lib/roby/test/execution_expectations.rb +1134 -0
- data/lib/roby/test/expect_execution.rb +151 -0
- data/lib/roby/test/minitest_helpers.rb +166 -0
- data/lib/roby/test/roby_app_helpers.rb +200 -0
- data/lib/roby/test/run_planners.rb +155 -0
- data/lib/roby/test/self.rb +112 -0
- data/lib/roby/test/spec.rb +198 -0
- data/lib/roby/test/tasks/empty_task.rb +4 -4
- data/lib/roby/test/tasks/goto.rb +28 -27
- data/lib/roby/test/teardown_plans.rb +100 -0
- data/lib/roby/test/testcase.rb +239 -307
- data/lib/roby/test/tools.rb +159 -155
- data/lib/roby/test/validate_state_machine.rb +75 -0
- data/lib/roby/transaction.rb +1125 -0
- data/lib/roby/transaction/event_generator_proxy.rb +63 -0
- data/lib/roby/transaction/plan_object_proxy.rb +99 -0
- data/lib/roby/transaction/plan_service_proxy.rb +43 -0
- data/lib/roby/transaction/proxying.rb +120 -0
- data/lib/roby/transaction/task_event_generator_proxy.rb +19 -0
- data/lib/roby/transaction/task_proxy.rb +135 -0
- data/lib/roby/until_generator.rb +30 -0
- data/lib/roby/version.rb +5 -0
- data/lib/roby/yard.rb +169 -0
- data/lib/yard-roby.rb +1 -0
- data/manifest.xml +32 -6
- data/roby.gemspec +59 -0
- metadata +788 -587
- data/Manifest.txt +0 -321
- data/NOTES +0 -4
- data/README.txt +0 -166
- data/TODO.txt +0 -146
- data/app/README.txt +0 -24
- data/app/Rakefile +0 -8
- data/app/config/ROBOT.rb +0 -5
- data/app/config/init.rb +0 -33
- data/app/config/roby.yml +0 -3
- data/app/controllers/ROBOT.rb +0 -2
- data/app/planners/ROBOT/main.rb +0 -6
- data/app/planners/main.rb +0 -5
- data/app/scripts/distributed +0 -3
- data/app/scripts/generate/bookmarks +0 -3
- data/app/scripts/replay +0 -3
- data/app/scripts/results +0 -3
- data/app/scripts/run +0 -3
- data/app/scripts/server +0 -3
- data/app/scripts/shell +0 -3
- data/app/scripts/test +0 -3
- data/app/tasks/.gitattributes +0 -0
- data/app/tasks/ROBOT/.gitattributes +0 -0
- data/bin/roby-shell +0 -25
- data/doc/guide/src/basics/app.page +0 -139
- data/doc/guide/src/basics/index.page +0 -11
- data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/basics/relations_display.page +0 -203
- data/doc/guide/src/basics/shell.page +0 -102
- data/doc/guide/src/default.css +0 -319
- data/doc/guide/src/introduction/index.page +0 -29
- data/doc/guide/src/introduction/publications.page +0 -14
- data/doc/guide/src/relations/dependency.page +0 -89
- data/doc/guide/src/relations/index.page +0 -12
- data/ext/droby/dump.cc +0 -175
- data/ext/droby/extconf.rb +0 -3
- data/ext/graph/algorithm.cc +0 -746
- data/ext/graph/extconf.rb +0 -7
- data/ext/graph/graph.cc +0 -575
- data/ext/graph/graph.hh +0 -183
- data/ext/graph/iterator_sequence.hh +0 -102
- data/ext/graph/undirected_dfs.hh +0 -226
- data/ext/graph/undirected_graph.hh +0 -421
- data/lib/roby/app/scripts/generate/bookmarks.rb +0 -162
- data/lib/roby/app/scripts/replay.rb +0 -31
- data/lib/roby/app/scripts/server.rb +0 -18
- data/lib/roby/basic_object.rb +0 -151
- data/lib/roby/config.rb +0 -14
- data/lib/roby/distributed.rb +0 -36
- data/lib/roby/distributed/base.rb +0 -448
- data/lib/roby/distributed/communication.rb +0 -875
- data/lib/roby/distributed/connection_space.rb +0 -616
- data/lib/roby/distributed/distributed_object.rb +0 -206
- data/lib/roby/distributed/drb.rb +0 -62
- data/lib/roby/distributed/notifications.rb +0 -531
- data/lib/roby/distributed/peer.rb +0 -555
- data/lib/roby/distributed/protocol.rb +0 -529
- data/lib/roby/distributed/proxy.rb +0 -343
- data/lib/roby/distributed/subscription.rb +0 -311
- data/lib/roby/distributed/transaction.rb +0 -498
- data/lib/roby/external_process_task.rb +0 -225
- data/lib/roby/graph.rb +0 -160
- data/lib/roby/log.rb +0 -3
- data/lib/roby/log/chronicle.rb +0 -303
- data/lib/roby/log/console.rb +0 -74
- data/lib/roby/log/data_stream.rb +0 -275
- data/lib/roby/log/dot.rb +0 -279
- data/lib/roby/log/event_stream.rb +0 -161
- data/lib/roby/log/file.rb +0 -396
- data/lib/roby/log/gui/basic_display.ui +0 -83
- data/lib/roby/log/gui/basic_display_ui.rb +0 -89
- data/lib/roby/log/gui/chronicle.rb +0 -26
- data/lib/roby/log/gui/chronicle_view.rb +0 -40
- data/lib/roby/log/gui/chronicle_view.ui +0 -70
- data/lib/roby/log/gui/chronicle_view_ui.rb +0 -90
- data/lib/roby/log/gui/data_displays.rb +0 -171
- data/lib/roby/log/gui/data_displays.ui +0 -155
- data/lib/roby/log/gui/data_displays_ui.rb +0 -146
- data/lib/roby/log/gui/notifications.rb +0 -26
- data/lib/roby/log/gui/relations.rb +0 -269
- data/lib/roby/log/gui/relations.ui +0 -123
- data/lib/roby/log/gui/relations_ui.rb +0 -120
- data/lib/roby/log/gui/relations_view.rb +0 -185
- data/lib/roby/log/gui/relations_view.ui +0 -149
- data/lib/roby/log/gui/relations_view_ui.rb +0 -144
- data/lib/roby/log/gui/replay.rb +0 -366
- data/lib/roby/log/gui/replay_controls.rb +0 -206
- data/lib/roby/log/gui/replay_controls.ui +0 -282
- data/lib/roby/log/gui/replay_controls_ui.rb +0 -249
- data/lib/roby/log/gui/runtime.rb +0 -130
- data/lib/roby/log/hooks.rb +0 -186
- data/lib/roby/log/logger.rb +0 -203
- data/lib/roby/log/notifications.rb +0 -244
- data/lib/roby/log/plan_rebuilder.rb +0 -468
- data/lib/roby/log/relations.rb +0 -1084
- data/lib/roby/log/server.rb +0 -547
- data/lib/roby/log/sqlite.rb +0 -47
- data/lib/roby/log/timings.rb +0 -233
- data/lib/roby/plan-object.rb +0 -371
- data/lib/roby/planning.rb +0 -13
- data/lib/roby/planning/loops.rb +0 -309
- data/lib/roby/planning/model.rb +0 -1012
- data/lib/roby/planning/task.rb +0 -180
- data/lib/roby/query.rb +0 -655
- data/lib/roby/relations/conflicts.rb +0 -67
- data/lib/roby/relations/dependency.rb +0 -358
- data/lib/roby/relations/ensured.rb +0 -19
- data/lib/roby/relations/error_handling.rb +0 -22
- data/lib/roby/relations/events.rb +0 -7
- data/lib/roby/relations/executed_by.rb +0 -208
- data/lib/roby/relations/influence.rb +0 -10
- data/lib/roby/relations/planned_by.rb +0 -63
- data/lib/roby/state/information.rb +0 -55
- data/lib/roby/state/state.rb +0 -367
- data/lib/roby/task-operations.rb +0 -186
- data/lib/roby/task_index.rb +0 -80
- data/lib/roby/test/distributed.rb +0 -230
- data/lib/roby/test/tasks/simple_task.rb +0 -23
- data/lib/roby/transactions.rb +0 -507
- data/lib/roby/transactions/proxy.rb +0 -325
- data/plugins/fault_injection/History.txt +0 -4
- data/plugins/fault_injection/README.txt +0 -34
- data/plugins/fault_injection/Rakefile +0 -12
- data/plugins/fault_injection/TODO.txt +0 -0
- data/plugins/fault_injection/app.rb +0 -52
- data/plugins/fault_injection/fault_injection.rb +0 -89
- data/plugins/fault_injection/test/test_fault_injection.rb +0 -78
- data/plugins/subsystems/README.txt +0 -37
- data/plugins/subsystems/Rakefile +0 -13
- data/plugins/subsystems/app.rb +0 -182
- data/plugins/subsystems/test/app/README +0 -24
- data/plugins/subsystems/test/app/Rakefile +0 -8
- data/plugins/subsystems/test/app/config/app.yml +0 -71
- data/plugins/subsystems/test/app/config/init.rb +0 -12
- data/plugins/subsystems/test/app/config/roby.yml +0 -3
- data/plugins/subsystems/test/app/planners/main.rb +0 -20
- data/plugins/subsystems/test/app/scripts/distributed +0 -3
- data/plugins/subsystems/test/app/scripts/replay +0 -3
- data/plugins/subsystems/test/app/scripts/results +0 -3
- data/plugins/subsystems/test/app/scripts/run +0 -3
- data/plugins/subsystems/test/app/scripts/server +0 -3
- data/plugins/subsystems/test/app/scripts/shell +0 -3
- data/plugins/subsystems/test/app/scripts/test +0 -3
- data/plugins/subsystems/test/app/tasks/services.rb +0 -15
- data/plugins/subsystems/test/test_subsystems.rb +0 -78
- data/test/distributed/test_communication.rb +0 -195
- data/test/distributed/test_connection.rb +0 -284
- data/test/distributed/test_execution.rb +0 -378
- data/test/distributed/test_mixed_plan.rb +0 -341
- data/test/distributed/test_plan_notifications.rb +0 -238
- data/test/distributed/test_protocol.rb +0 -525
- data/test/distributed/test_query.rb +0 -106
- data/test/distributed/test_remote_plan.rb +0 -491
- data/test/distributed/test_transaction.rb +0 -466
- data/test/mockups/external_process +0 -28
- data/test/mockups/tasks.rb +0 -27
- data/test/planning/test_loops.rb +0 -432
- data/test/planning/test_model.rb +0 -427
- data/test/planning/test_task.rb +0 -126
- data/test/relations/test_conflicts.rb +0 -42
- data/test/relations/test_dependency.rb +0 -324
- data/test/relations/test_ensured.rb +0 -38
- data/test/relations/test_executed_by.rb +0 -224
- data/test/relations/test_planned_by.rb +0 -56
- data/test/suite_core.rb +0 -29
- data/test/suite_distributed.rb +0 -10
- data/test/suite_planning.rb +0 -4
- data/test/suite_relations.rb +0 -8
- data/test/tasks/test_external_process.rb +0 -126
- data/test/tasks/test_thread_task.rb +0 -70
- data/test/test_bgl.rb +0 -528
- data/test/test_event.rb +0 -969
- data/test/test_exceptions.rb +0 -591
- data/test/test_execution_engine.rb +0 -987
- data/test/test_gui.rb +0 -20
- data/test/test_interface.rb +0 -43
- data/test/test_log.rb +0 -125
- data/test/test_log_server.rb +0 -133
- data/test/test_plan.rb +0 -418
- data/test/test_query.rb +0 -424
- data/test/test_relations.rb +0 -260
- data/test/test_state.rb +0 -432
- data/test/test_support.rb +0 -16
- data/test/test_task.rb +0 -1181
- data/test/test_testcase.rb +0 -138
- data/test/test_transactions.rb +0 -610
- data/test/test_transactions_proxy.rb +0 -216
|
@@ -0,0 +1,835 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
# This namespace contains predicates that allow to specify logic ordering
|
|
3
|
+
# constraints between events. The predicate objects can then be evaluated
|
|
4
|
+
# (return true/false), and can tell whether their value may change in the
|
|
5
|
+
# future.
|
|
6
|
+
#
|
|
7
|
+
# Moreover, for all three states (true, false, and static), the predicates
|
|
8
|
+
# can explain which events and/or generators explain this state of the
|
|
9
|
+
# predicate.
|
|
10
|
+
#
|
|
11
|
+
# For instance,
|
|
12
|
+
#
|
|
13
|
+
# pred = :intermediate.to_unbound_task_predicate
|
|
14
|
+
#
|
|
15
|
+
# is a predicate that will return true if the intermediate event of the task
|
|
16
|
+
# it represents has already been emitted, and false otherwise.
|
|
17
|
+
#
|
|
18
|
+
# pred.evaluate(task) => true or false
|
|
19
|
+
#
|
|
20
|
+
# If task.intermediate? is true (the event has been emitted), then
|
|
21
|
+
#
|
|
22
|
+
# pred.explain_true(task)
|
|
23
|
+
#
|
|
24
|
+
# will return an Explanation instance where +elements+ ==
|
|
25
|
+
# [pred.intermediate_event.last] (the Event instance that has been emitted).
|
|
26
|
+
#
|
|
27
|
+
# However, if the event is not yet emitted then,
|
|
28
|
+
#
|
|
29
|
+
# pred.explain_false(task) => #<Explanation @elements=[pred.intermediate_event]>
|
|
30
|
+
#
|
|
31
|
+
# i.e. the reason is that intermediate_event has not been emitted.
|
|
32
|
+
#
|
|
33
|
+
# Finally, if intermediate has never been emitted and the task is finished
|
|
34
|
+
# (let's say because success has been emitted), the intermediate event
|
|
35
|
+
# cannot be emitted anymore. In this case,
|
|
36
|
+
#
|
|
37
|
+
# pred.static?(task) => true
|
|
38
|
+
# pred.evaluate(task) => false
|
|
39
|
+
# pred.explain_static(task) => #<Explanation @elements=[task.event(:success)]>
|
|
40
|
+
#
|
|
41
|
+
module EventConstraints
|
|
42
|
+
# Module that defines the unbound task predicate methods that are
|
|
43
|
+
# added to the Symbol class
|
|
44
|
+
module UnboundPredicateSupport
|
|
45
|
+
# Returns an UnboundTaskPredicate that will be true if the generator
|
|
46
|
+
# represented by this symbol has emitted at least once.
|
|
47
|
+
#
|
|
48
|
+
# In its simplest form,
|
|
49
|
+
#
|
|
50
|
+
# :blocked.emitted?
|
|
51
|
+
#
|
|
52
|
+
# will be true when evaluated on a task whose +blocked+ event has
|
|
53
|
+
# emitted at least once
|
|
54
|
+
def emitted?
|
|
55
|
+
to_unbound_task_predicate
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @deprecated use {#emitted?} instead
|
|
59
|
+
def happened?
|
|
60
|
+
Roby.warn_deprecated "#happened? is deprecated, use #emitted? instead"
|
|
61
|
+
emitted?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Protocol method. The unbound task predicate call always calls
|
|
65
|
+
# #to_unbound_task_predicate on the arguments given to it.
|
|
66
|
+
def to_unbound_task_predicate
|
|
67
|
+
UnboundTaskPredicate::SingleEvent.new(self)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Returns an UnboundTaskPredicate that will be true if the generator
|
|
71
|
+
# represented by this symbol will never be emitted.
|
|
72
|
+
#
|
|
73
|
+
# In its simplest form,
|
|
74
|
+
#
|
|
75
|
+
# :blocked.never
|
|
76
|
+
#
|
|
77
|
+
# will be true when evaluated on a task whose +blocked+ event has
|
|
78
|
+
# not yet been emitted, and has been declared as unreachable
|
|
79
|
+
def never
|
|
80
|
+
to_unbound_task_predicate.never
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Returns an UnboundTaskPredicate that will be true if the generator
|
|
84
|
+
# represented by this symbol has emitted at least once, and the
|
|
85
|
+
# predicate represented by +other+ is true at the same time.
|
|
86
|
+
#
|
|
87
|
+
# In its simplest form,
|
|
88
|
+
#
|
|
89
|
+
# :blocked.and(:updated)
|
|
90
|
+
#
|
|
91
|
+
# it will be true if the task on which it is applied has both
|
|
92
|
+
# emitted :blocked and :updated at least once.
|
|
93
|
+
def and(other)
|
|
94
|
+
to_unbound_task_predicate.
|
|
95
|
+
and(other.to_unbound_task_predicate)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Returns an UnboundTaskPredicate that will be true if the generator
|
|
99
|
+
# represented by this symbol has emitted at least once, or the
|
|
100
|
+
# predicate represented by +other+ is true.
|
|
101
|
+
#
|
|
102
|
+
# In its simplest form,
|
|
103
|
+
#
|
|
104
|
+
# :blocked.or(:updated)
|
|
105
|
+
#
|
|
106
|
+
# it will be true if the task on which it is applied has either
|
|
107
|
+
# emitted :blocked, or emitted :updated, or both.
|
|
108
|
+
def or(other)
|
|
109
|
+
to_unbound_task_predicate.
|
|
110
|
+
or(other.to_unbound_task_predicate)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Returns an UnboundTaskPredicate that will be true if the generator
|
|
114
|
+
# represented by this symbol and the generator represented by
|
|
115
|
+
# +other+ (as a symbol) have emitted in sequence, i.e. if both
|
|
116
|
+
# +self+ and +other+ have emitted at least once, and if the last
|
|
117
|
+
# event e0 emitted by +self+ and the last event e1 emitted by
|
|
118
|
+
# +other+ match
|
|
119
|
+
#
|
|
120
|
+
# e0.time < e1.time
|
|
121
|
+
#
|
|
122
|
+
# Unlike +and+, +or+ and +negate+, this only works on single events
|
|
123
|
+
# (i.e. it cannot be applied on other predicates)
|
|
124
|
+
def followed_by(other)
|
|
125
|
+
to_unbound_task_predicate.
|
|
126
|
+
followed_by(other.to_unbound_task_predicate)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Returns an UnboundTaskPredicate that will be true if the generator
|
|
130
|
+
# represented by this symbol and the generator represented by
|
|
131
|
+
# +other+ (as a symbol) have not emitted in sequence, i.e. if +self+
|
|
132
|
+
# has emitted at least once, and either +other+ has not emitted or
|
|
133
|
+
# +other+ has emitted and the last event e0 emitted by +self+ and
|
|
134
|
+
# the last event e1 emitted by +other+ do not match
|
|
135
|
+
#
|
|
136
|
+
# e0.time < e1.time
|
|
137
|
+
#
|
|
138
|
+
# Unlike +and+, +or+ and +negate+, this only works on single events
|
|
139
|
+
# (i.e. it cannot be applied on other predicates)
|
|
140
|
+
def not_followed_by(other)
|
|
141
|
+
to_unbound_task_predicate.
|
|
142
|
+
not_followed_by(other.to_unbound_task_predicate)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Returns an UnboundTaskPredicate that will be true if the generator
|
|
146
|
+
# represented by +self+ has never emitted
|
|
147
|
+
def negate
|
|
148
|
+
to_unbound_task_predicate.negate
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
::Symbol.include UnboundPredicateSupport
|
|
152
|
+
|
|
153
|
+
class ::FalseClass
|
|
154
|
+
# Returns an UnboundTaskPredicate object that will always evaluate
|
|
155
|
+
# to false
|
|
156
|
+
def to_unbound_task_predicate
|
|
157
|
+
Roby::EventConstraints::UnboundTaskPredicate::False.new
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Represents a temporal logic predicate that applies on the internal
|
|
162
|
+
# events of a single task. As the events are represented by their name,
|
|
163
|
+
# the predicate can be reused to be applied on different tasks.
|
|
164
|
+
class UnboundTaskPredicate
|
|
165
|
+
def to_unbound_task_predicate
|
|
166
|
+
self
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Returns a predicate that is true if both +self+ and
|
|
170
|
+
# +other_predicate+ are true.
|
|
171
|
+
#
|
|
172
|
+
# Because of the "and" semantic, the predicate is static if one of
|
|
173
|
+
# the two predicates is false and static, or if both predicates
|
|
174
|
+
# are static.
|
|
175
|
+
def and(other_predicate)
|
|
176
|
+
if self == other_predicate then self
|
|
177
|
+
elsif other_predicate.kind_of?(UnboundTaskPredicate::False)
|
|
178
|
+
other_predicate
|
|
179
|
+
else
|
|
180
|
+
And.new(self, other_predicate)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Returns a predicate that is true if either or both of +self+ and
|
|
185
|
+
# +other_predicate+ are true.
|
|
186
|
+
#
|
|
187
|
+
# Because of the "or" semantic, the predicate is static if one of
|
|
188
|
+
# the two predicates are true and static, or if both predicates
|
|
189
|
+
# are static.
|
|
190
|
+
def or(other_predicate)
|
|
191
|
+
if self == other_predicate then self
|
|
192
|
+
elsif other_predicate.kind_of?(UnboundTaskPredicate::False)
|
|
193
|
+
self
|
|
194
|
+
else
|
|
195
|
+
Or.new(self, other_predicate)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Returns a predicate that is the negation of +self+
|
|
200
|
+
#
|
|
201
|
+
# Because of the "not" semantic, the predicate is static if +self+
|
|
202
|
+
# is static.
|
|
203
|
+
def negate
|
|
204
|
+
Negate.new(self)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Returns an Explanation object that explains why +self+ is true.
|
|
208
|
+
# Note that it is valid only if evaluate(task) actually returned
|
|
209
|
+
# true (it will silently return an invalid explanation if
|
|
210
|
+
# evaluate(task) returns false).
|
|
211
|
+
def explain_true(task); nil end
|
|
212
|
+
|
|
213
|
+
# Returns an Explanation object that explains why +self+ is false.
|
|
214
|
+
# Note that it is valid only if evaluate(task) actually returned
|
|
215
|
+
# false (it will silently return an invalid explanation if
|
|
216
|
+
# evaluate(task) returns true).
|
|
217
|
+
def explain_false(task); nil end
|
|
218
|
+
|
|
219
|
+
# Returns an Explanation object that explains why +self+ will not
|
|
220
|
+
# change its value anymore.
|
|
221
|
+
#
|
|
222
|
+
# Note that it is valid only if static?(task) actually returned
|
|
223
|
+
# true (it will silently return an invalid explanation otherwise)
|
|
224
|
+
def explain_static(task)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def pretty_print(pp)
|
|
228
|
+
pp.text to_s
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# See #compile.
|
|
232
|
+
#
|
|
233
|
+
# Objects of this class hold the compiled predicate used for
|
|
234
|
+
# evaluation
|
|
235
|
+
class CompiledPredicate
|
|
236
|
+
def marshal_dump; nil end
|
|
237
|
+
def marshal_load(obj); nil end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Predicates are first represented as an AST using the subclasses of
|
|
241
|
+
# UnboundTaskPredicate, but are then compiled into code before being
|
|
242
|
+
# evaluated (for performance reasons).
|
|
243
|
+
#
|
|
244
|
+
# This is the main call that performs this compilation
|
|
245
|
+
def compile
|
|
246
|
+
prelude = required_events.map do |event_name|
|
|
247
|
+
" task_event_#{event_name} = task.event(:#{event_name})\n" +
|
|
248
|
+
" task_#{event_name} = task_event_#{event_name}.last"
|
|
249
|
+
end.join("\n")
|
|
250
|
+
|
|
251
|
+
compiled_predicate = CompiledPredicate.new
|
|
252
|
+
eval <<-END, binding, __FILE__, __LINE__+1
|
|
253
|
+
def compiled_predicate.evaluate(task)
|
|
254
|
+
#{prelude}
|
|
255
|
+
#{code}
|
|
256
|
+
end
|
|
257
|
+
END
|
|
258
|
+
@compiled_predicate = compiled_predicate
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Evaluates this predicate on +task+. It returns either true or
|
|
262
|
+
# false.
|
|
263
|
+
def evaluate(task)
|
|
264
|
+
compile if !@compiled_predicate || !@compiled_predicate.respond_to?(:evaluate)
|
|
265
|
+
@compiled_predicate.evaluate(task)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# An explanation for a given predicate value. +predicate+ is the
|
|
270
|
+
# predicate, +elements+ the explanations for +predicate+ having reached
|
|
271
|
+
# the value.
|
|
272
|
+
#
|
|
273
|
+
# +elements+ is an array of Event and EventGenerator instances.
|
|
274
|
+
#
|
|
275
|
+
# If an Event is stored there, the explanation is that this event has
|
|
276
|
+
# been emitted.
|
|
277
|
+
#
|
|
278
|
+
# If an EventGenerator is stored there, the reason depends on +value+.
|
|
279
|
+
# If +value+ is nil (static), the reason is that the generator is
|
|
280
|
+
# unreachable. If +value+ is false (not emitted), it is that the
|
|
281
|
+
# generator did not emit.
|
|
282
|
+
class Explanation
|
|
283
|
+
# Representation of what is being explained. It is true if it is
|
|
284
|
+
# explaining why a predicate is true, false if it is explaining why
|
|
285
|
+
# it is false and nil for static.
|
|
286
|
+
attr_accessor :value
|
|
287
|
+
# The predicate that we are providing an explanation for
|
|
288
|
+
attr_reader :predicate
|
|
289
|
+
# The elements of explanation
|
|
290
|
+
attr_reader :elements
|
|
291
|
+
|
|
292
|
+
def simple?
|
|
293
|
+
elements.size == 1 && !elements.first.kind_of?(Explanation)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def initialize(value, predicate, elements)
|
|
297
|
+
@value, @predicate, @elements = value, predicate, elements
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def report_exceptions_on(e)
|
|
301
|
+
elements.each do |el|
|
|
302
|
+
case el
|
|
303
|
+
when Explanation
|
|
304
|
+
el.report_exceptions_on(e)
|
|
305
|
+
when Exception
|
|
306
|
+
e.report_exceptions_from(el)
|
|
307
|
+
when Event
|
|
308
|
+
el.all_sources.each do |ev|
|
|
309
|
+
e.report_exceptions_from(ev)
|
|
310
|
+
end
|
|
311
|
+
when EventGenerator
|
|
312
|
+
if value == nil
|
|
313
|
+
e.report_exceptions_from(el.unreachability_reason)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def pretty_print(pp)
|
|
320
|
+
if value == false
|
|
321
|
+
predicate.pretty_print(pp)
|
|
322
|
+
pp.text " is false"
|
|
323
|
+
elsif value == true
|
|
324
|
+
predicate.pretty_print(pp)
|
|
325
|
+
pp.text " is true"
|
|
326
|
+
elsif value == nil
|
|
327
|
+
pp.text "the value of "
|
|
328
|
+
predicate.pretty_print(pp)
|
|
329
|
+
pp.text " will not change anymore"
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
pp.nest(2) do
|
|
333
|
+
elements.each do |explanation|
|
|
334
|
+
pp.breakable
|
|
335
|
+
case explanation
|
|
336
|
+
when Event
|
|
337
|
+
pp.text "the following event has been emitted "
|
|
338
|
+
when EventGenerator
|
|
339
|
+
if value == nil
|
|
340
|
+
pp.text "the following event is unreachable "
|
|
341
|
+
elsif value == true
|
|
342
|
+
pp.text "the following event is reachable, but has not been emitted "
|
|
343
|
+
else
|
|
344
|
+
pp.text "the following event has been emitted "
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
explanation.pretty_print(pp)
|
|
349
|
+
case explanation
|
|
350
|
+
when Event
|
|
351
|
+
sources = explanation.all_sources
|
|
352
|
+
if !sources.empty?
|
|
353
|
+
pp.breakable
|
|
354
|
+
pp.text "The emission was caused by the following events"
|
|
355
|
+
sources.each do |ev|
|
|
356
|
+
pp.breakable
|
|
357
|
+
pp.text "< "
|
|
358
|
+
ev.pretty_print(pp, false)
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
when EventGenerator
|
|
363
|
+
if value == nil && explanation.unreachability_reason
|
|
364
|
+
pp.breakable
|
|
365
|
+
pp.text "The unreachability was caused by "
|
|
366
|
+
pp.nest(2) do
|
|
367
|
+
pp.breakable
|
|
368
|
+
explanation.unreachability_reason.pretty_print(pp)
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
else
|
|
372
|
+
explanation.pretty_print(pp)
|
|
373
|
+
end
|
|
374
|
+
pp.breakable
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Representation of a predicate that is always false
|
|
381
|
+
class UnboundTaskPredicate::False < UnboundTaskPredicate
|
|
382
|
+
def required_events; Set.new end
|
|
383
|
+
def explain_true(task); Hash.new end
|
|
384
|
+
def explain_false(task); Hash.new end
|
|
385
|
+
def explain_static(task); Hash.new end
|
|
386
|
+
def evaluate(task); false end
|
|
387
|
+
def static?(task); true end
|
|
388
|
+
def to_s; "false" end
|
|
389
|
+
|
|
390
|
+
def ==(pred); pred.kind_of?(False) end
|
|
391
|
+
|
|
392
|
+
def code
|
|
393
|
+
"false"
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def or(pred); pred end
|
|
397
|
+
def and(pred); self end
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# Representation of predicates UnboundPredicateSupport#negate and
|
|
401
|
+
# UnboundTaskPredicate#negate
|
|
402
|
+
#
|
|
403
|
+
# See documentation from UnboundTaskPredicate
|
|
404
|
+
class UnboundTaskPredicate::Negate < UnboundTaskPredicate
|
|
405
|
+
attr_reader :predicate
|
|
406
|
+
def initialize(pred)
|
|
407
|
+
@predicate = pred
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
def ==(pred); pred.kind_of?(Negate) && pred.predicate == predicate end
|
|
411
|
+
|
|
412
|
+
def explain_true(task); predicate.explain_false(task) end
|
|
413
|
+
def explain_false(task); predicate.explain_true(task) end
|
|
414
|
+
def explain_static(task); predicate.explain_static(task) end
|
|
415
|
+
|
|
416
|
+
def required_events; predicate.required_events end
|
|
417
|
+
def code
|
|
418
|
+
"!(#{predicate.code})"
|
|
419
|
+
end
|
|
420
|
+
def static?(task); predicate.static?(task) end
|
|
421
|
+
def to_s; "!#{predicate}" end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Representation of UnboundPredicateSupport#never
|
|
425
|
+
#
|
|
426
|
+
# See documentation from UnboundPredicateSupport
|
|
427
|
+
class UnboundTaskPredicate::Never < UnboundTaskPredicate
|
|
428
|
+
attr_reader :predicate
|
|
429
|
+
def initialize(pred)
|
|
430
|
+
if !pred.kind_of?(UnboundTaskPredicate::SingleEvent)
|
|
431
|
+
raise ArgumentError, "can only create a Never predicate on top of a SingleEvent"
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
@predicate = pred
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def ==(pred); pred.kind_of?(Never) && pred.predicate == predicate end
|
|
438
|
+
|
|
439
|
+
def explain_true(task)
|
|
440
|
+
return if !evaluate(task)
|
|
441
|
+
predicate.explain_static(task)
|
|
442
|
+
end
|
|
443
|
+
def explain_false(task)
|
|
444
|
+
return if evaluate(task)
|
|
445
|
+
if predicate.evaluate(task)
|
|
446
|
+
predicate.explain_true(task)
|
|
447
|
+
elsif !predicate.static?(task)
|
|
448
|
+
explanation = predicate.explain_false(task)
|
|
449
|
+
explanation.value = true
|
|
450
|
+
explanation
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
def explain_static(task)
|
|
454
|
+
if predicate.evaluate(task)
|
|
455
|
+
predicate.explain_true(task)
|
|
456
|
+
else
|
|
457
|
+
predicate.explain_static(task)
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
def required_events; predicate.required_events end
|
|
462
|
+
def code
|
|
463
|
+
"(!task_#{predicate.event_name} && task_event_#{predicate.event_name}.unreachable?)"
|
|
464
|
+
end
|
|
465
|
+
def static?(task)
|
|
466
|
+
evaluate(task) || predicate.static?(task)
|
|
467
|
+
end
|
|
468
|
+
def to_s; "never(#{predicate})" end
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# Representation of a binary combination of predicates that is
|
|
472
|
+
# commutative. It is used to simplify expressions, especially for
|
|
473
|
+
# explanations.
|
|
474
|
+
class UnboundTaskPredicate::BinaryCommutativePredicate < UnboundTaskPredicate
|
|
475
|
+
attr_reader :predicates
|
|
476
|
+
def initialize(left, right)
|
|
477
|
+
@predicates = [left, right]
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def required_events; predicates[0].required_events | predicates[1].required_events end
|
|
481
|
+
|
|
482
|
+
def ==(pred)
|
|
483
|
+
pred.kind_of?(self.class) &&
|
|
484
|
+
((predicates[0] == pred.predicates[0] && predicates[1] == pred.predicates[1]) ||
|
|
485
|
+
(predicates[0] == pred.predicates[1] && predicates[1] == pred.predicates[0]))
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def explain_true(task)
|
|
489
|
+
return if !evaluate(task)
|
|
490
|
+
|
|
491
|
+
reason0 = predicates[0].explain_true(task)
|
|
492
|
+
reason1 = predicates[1].explain_true(task)
|
|
493
|
+
if reason0 && reason1
|
|
494
|
+
Explanation.new(true, self, [reason0, reason1])
|
|
495
|
+
else
|
|
496
|
+
reason0 || reason1
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
def explain_false(task)
|
|
500
|
+
return if evaluate(task)
|
|
501
|
+
|
|
502
|
+
reason0 = predicates[0].explain_false(task)
|
|
503
|
+
reason1 = predicates[1].explain_false(task)
|
|
504
|
+
if reason0 && reason1
|
|
505
|
+
Explanation.new(false, self, [reason0, reason1])
|
|
506
|
+
else
|
|
507
|
+
reason0 || reason1
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
def explain_static(task)
|
|
511
|
+
return if !static?(task)
|
|
512
|
+
|
|
513
|
+
reason0 = predicates[0].explain_static(task)
|
|
514
|
+
reason1 = predicates[1].explain_static(task)
|
|
515
|
+
if reason0 && reason1
|
|
516
|
+
Explanation.new(nil, self, [reason0, reason1])
|
|
517
|
+
else
|
|
518
|
+
reason0 || reason1
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def has_atomic_predicate?(pred)
|
|
523
|
+
pred = pred.to_unbound_task_predicate
|
|
524
|
+
each_atomic_predicate do |p|
|
|
525
|
+
return(true) if p == pred
|
|
526
|
+
end
|
|
527
|
+
false
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def each_atomic_predicate(&block)
|
|
531
|
+
2.times do |i|
|
|
532
|
+
if predicates[i].kind_of?(self.class)
|
|
533
|
+
predicates[i].each_atomic_predicate(&block)
|
|
534
|
+
else
|
|
535
|
+
yield(predicates[i])
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
# Representation of UnboundPredicateSupport#and and
|
|
542
|
+
# UnboundTaskPredicate#and
|
|
543
|
+
#
|
|
544
|
+
# See documentation from UnboundTaskPredicate
|
|
545
|
+
class UnboundTaskPredicate::And < UnboundTaskPredicate::BinaryCommutativePredicate
|
|
546
|
+
def code
|
|
547
|
+
"(#{predicates[0].code}) && (#{predicates[1].code})"
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def and(pred)
|
|
551
|
+
pred = pred.to_unbound_task_predicate
|
|
552
|
+
if pred.kind_of?(And)
|
|
553
|
+
# Only add predicates in +pred+ that are not already in
|
|
554
|
+
# +self+
|
|
555
|
+
result = self
|
|
556
|
+
pred.each_atomic_predicate do |predicate|
|
|
557
|
+
result = result.and(predicate)
|
|
558
|
+
end
|
|
559
|
+
elsif has_atomic_predicate?(pred)
|
|
560
|
+
self
|
|
561
|
+
else
|
|
562
|
+
super
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
def static?(task)
|
|
567
|
+
static0 = predicates[0].static?(task)
|
|
568
|
+
static1 = predicates[1].static?(task)
|
|
569
|
+
static0 && static1 ||
|
|
570
|
+
(static0 && !predicates[0].evaluate(task) ||
|
|
571
|
+
static1 && !predicates[1].evaluate(task))
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
def explain_static(task)
|
|
575
|
+
static0 = predicates[0].static?(task)
|
|
576
|
+
static1 = predicates[1].static?(task)
|
|
577
|
+
if static0 && static1
|
|
578
|
+
super(task)
|
|
579
|
+
elsif static0 && !predicates[0].evaluate(task)
|
|
580
|
+
predicates[0].explain_static(task)
|
|
581
|
+
elsif static1 && !predicates[1].evaluate(task)
|
|
582
|
+
predicates[1].explain_static(task)
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
def to_s; "(#{predicates[0]}) && (#{predicates[1]})" end
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
# Representation of UnboundPredicateSupport#or and
|
|
590
|
+
# UnboundTaskPredicate#or
|
|
591
|
+
#
|
|
592
|
+
# See documentation from UnboundTaskPredicate
|
|
593
|
+
class UnboundTaskPredicate::Or < UnboundTaskPredicate::BinaryCommutativePredicate
|
|
594
|
+
def code
|
|
595
|
+
"(#{predicates[0].code}) || (#{predicates[1].code})"
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
def or(pred)
|
|
599
|
+
pred = pred.to_unbound_task_predicate
|
|
600
|
+
if pred.kind_of?(Or)
|
|
601
|
+
# Only add predicates in +pred+ that are not already in
|
|
602
|
+
# +self+
|
|
603
|
+
result = self
|
|
604
|
+
pred.each_atomic_predicate do |predicate|
|
|
605
|
+
result = result.or(predicate)
|
|
606
|
+
end
|
|
607
|
+
result
|
|
608
|
+
elsif has_atomic_predicate?(pred)
|
|
609
|
+
# Do not add +pred+ if it is already included in +self+
|
|
610
|
+
self
|
|
611
|
+
else
|
|
612
|
+
super
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def static?(task)
|
|
617
|
+
static0 = predicates[0].static?(task)
|
|
618
|
+
static1 = predicates[1].static?(task)
|
|
619
|
+
static0 && static1 ||
|
|
620
|
+
(static0 && predicates[0].evaluate(task) ||
|
|
621
|
+
static1 && predicates[1].evaluate(task))
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
def explain_static(task)
|
|
625
|
+
static0 = predicates[0].static?(task)
|
|
626
|
+
static1 = predicates[1].static?(task)
|
|
627
|
+
if static0 && static1
|
|
628
|
+
super(task)
|
|
629
|
+
elsif static0 && predicates[0].evaluate(task)
|
|
630
|
+
predicates[0].explain_static(task)
|
|
631
|
+
elsif static1 && predicates[1].evaluate(task)
|
|
632
|
+
predicates[1].explain_static(task)
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
def to_s; "(#{predicates[0]}) || (#{predicates[1]})" end
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
# Representation of UnboundPredicateSupport#followed_by
|
|
639
|
+
#
|
|
640
|
+
# See documentation from UnboundTaskPredicate
|
|
641
|
+
class UnboundTaskPredicate::FollowedBy < UnboundTaskPredicate::BinaryCommutativePredicate
|
|
642
|
+
def explain_true(task)
|
|
643
|
+
return if !evaluate(task)
|
|
644
|
+
|
|
645
|
+
this_event = task.event(predicates[0].event_name).last
|
|
646
|
+
other_event = task.event(predicates[1].event_name).last
|
|
647
|
+
Explanation.new(true, self, [this_event, other_event])
|
|
648
|
+
end
|
|
649
|
+
def explain_false(task)
|
|
650
|
+
return if evaluate(task)
|
|
651
|
+
|
|
652
|
+
this_generator = task.event(predicates[0].event_name)
|
|
653
|
+
other_generator = task.event(predicates[1].event_name)
|
|
654
|
+
if !this_generator.last
|
|
655
|
+
Explanation.new(false, self, [this_generator])
|
|
656
|
+
else
|
|
657
|
+
Explanation.new(false, self, [other_generator])
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
def explain_static(task)
|
|
661
|
+
return if !static?(task)
|
|
662
|
+
|
|
663
|
+
if predicates[0].static?(task)
|
|
664
|
+
this_generator = task.event(predicates[0].event_name)
|
|
665
|
+
if !predicates[0].evaluate(task) || evaluate(task)
|
|
666
|
+
Explanation.new(nil, self, [this_generator])
|
|
667
|
+
else # first event emitted, second event cannot be emitted (static)
|
|
668
|
+
other_generator = task.event(predicates[1].event_name)
|
|
669
|
+
Explanation.new(nil, self, [other_generator])
|
|
670
|
+
end
|
|
671
|
+
else
|
|
672
|
+
other_generator = task.event(predicates[1].event_name)
|
|
673
|
+
Explanation.new(nil, self, [other_generator])
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
def static?(task)
|
|
677
|
+
event0 = task.event(predicates[0].event_name)
|
|
678
|
+
event1 = task.event(predicates[1].event_name)
|
|
679
|
+
|
|
680
|
+
if event0.unreachable?
|
|
681
|
+
(!predicates[0].evaluate(task) || # will stay false as pred[0] can't emit
|
|
682
|
+
evaluate(task) || # will stay true as pred[0] can't emit
|
|
683
|
+
predicates[1].static?(task))
|
|
684
|
+
elsif event1.unreachable?
|
|
685
|
+
!evaluate(task)
|
|
686
|
+
end
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
def code
|
|
690
|
+
this_event = predicates[0].event_name
|
|
691
|
+
other_event = predicates[1].event_name
|
|
692
|
+
"(task_#{this_event} && task_#{other_event} && task_#{other_event}.time > task_#{this_event}.time)"
|
|
693
|
+
end
|
|
694
|
+
def to_s; "#{predicates[0].event_name}.followed_by(#{predicates[1].event_name})" end
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
# Representation of UnboundPredicateSupport#not_followed_by
|
|
698
|
+
#
|
|
699
|
+
# See documentation from UnboundTaskPredicate
|
|
700
|
+
class UnboundTaskPredicate::NotFollowedBy < UnboundTaskPredicate::BinaryCommutativePredicate
|
|
701
|
+
def explain_true(task)
|
|
702
|
+
return if !evaluate(task)
|
|
703
|
+
|
|
704
|
+
this_event = task.event(predicates[0].event_name).last
|
|
705
|
+
other_generator = task.event(predicates[1].event_name)
|
|
706
|
+
other_generator = other_generator.last || other_generator
|
|
707
|
+
Explanation.new(true, self, [this_event, other_generator])
|
|
708
|
+
end
|
|
709
|
+
def explain_false(task)
|
|
710
|
+
return if evaluate(task)
|
|
711
|
+
|
|
712
|
+
this_generator = task.event(predicates[0].event_name)
|
|
713
|
+
if !this_generator.last
|
|
714
|
+
Explanation.new(false, self, [this_generator])
|
|
715
|
+
else
|
|
716
|
+
other_generator = task.event(predicates[1].event_name)
|
|
717
|
+
Explanation.new(false, self, [other_generator.last])
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
def explain_static(task)
|
|
721
|
+
return if !static?(task)
|
|
722
|
+
|
|
723
|
+
if predicates[0].static?(task)
|
|
724
|
+
this_generator = task.event(predicates[0].event_name)
|
|
725
|
+
if !predicates[0].evaluate(task) || !evaluate(task)
|
|
726
|
+
Explanation.new(nil, self, [this_generator])
|
|
727
|
+
else
|
|
728
|
+
other_generator = task.event(predicates[1].event_name)
|
|
729
|
+
Explanation.new(nil, self, [this_generator, other_generator])
|
|
730
|
+
end
|
|
731
|
+
else
|
|
732
|
+
other_generator = task.event(predicates[1].event_name)
|
|
733
|
+
Explanation.new(nil, self, [other_generator])
|
|
734
|
+
end
|
|
735
|
+
end
|
|
736
|
+
def static?(task)
|
|
737
|
+
event0 = task.event(predicates[0].event_name)
|
|
738
|
+
event1 = task.event(predicates[1].event_name)
|
|
739
|
+
|
|
740
|
+
if event0.unreachable?
|
|
741
|
+
(!predicates[0].evaluate(task) || # stay false as first event can't emit
|
|
742
|
+
!evaluate(task) || # stay false as first event can't emit
|
|
743
|
+
predicates[1].static?(task))
|
|
744
|
+
elsif event1.unreachable?
|
|
745
|
+
evaluate(task) # stays true as the second event cannot
|
|
746
|
+
# appear after the first anymore
|
|
747
|
+
end
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
def code
|
|
751
|
+
this_event = predicates[0].event_name
|
|
752
|
+
other_event = predicates[1].event_name
|
|
753
|
+
"(task_#{this_event} && (!task_#{other_event} || task_#{other_event}.time < task_#{this_event}.time))"
|
|
754
|
+
end
|
|
755
|
+
def to_s; "#{predicates[0].event_name}.not_followed_by(#{predicates[1].event_name})" end
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
# Subclass of UnboundTaskPredicate to handle single event generators
|
|
759
|
+
#
|
|
760
|
+
# This is the class that is e.g. returned by
|
|
761
|
+
# UnboundPredicateSupport#to_unbound_task_predicate
|
|
762
|
+
class UnboundTaskPredicate::SingleEvent < UnboundTaskPredicate
|
|
763
|
+
# The generator name as a symbol
|
|
764
|
+
attr_reader :event_name
|
|
765
|
+
# The set of events required to compute this predicate. This is used
|
|
766
|
+
# by UnboundTaskPredicate#compile
|
|
767
|
+
attr_reader :required_events
|
|
768
|
+
|
|
769
|
+
def initialize(event_name)
|
|
770
|
+
@event_name = event_name
|
|
771
|
+
@required_events = [event_name].to_set
|
|
772
|
+
super()
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
def ==(pred); pred.kind_of?(SingleEvent) && pred.event_name == event_name end
|
|
776
|
+
|
|
777
|
+
# Code generation to create the overall evaluated predicate
|
|
778
|
+
def code
|
|
779
|
+
if @deadline
|
|
780
|
+
return "task_#{event_name} && (task_#{event_name}.time.to_f > #{@deadline.to_f})"
|
|
781
|
+
else
|
|
782
|
+
"!!task_#{event_name}"
|
|
783
|
+
end
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
# Returns an Explanation object that explains why +self+ is true.
|
|
787
|
+
# Note that it is valid only if evaluate(task) actually returned
|
|
788
|
+
# true (it will silently return an invalid explanation if
|
|
789
|
+
# evaluate(task) returns false).
|
|
790
|
+
def explain_true(task)
|
|
791
|
+
if event = task.event(event_name).last
|
|
792
|
+
Explanation.new(true, self, [event])
|
|
793
|
+
end
|
|
794
|
+
end
|
|
795
|
+
def explain_false(task)
|
|
796
|
+
generator = task.event(event_name)
|
|
797
|
+
if !generator.emitted?
|
|
798
|
+
Explanation.new(false, self, [generator])
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
def explain_static(task)
|
|
802
|
+
event = task.event(event_name)
|
|
803
|
+
if event.last
|
|
804
|
+
Explanation.new(true, self, [event.last])
|
|
805
|
+
elsif event.unreachable?
|
|
806
|
+
Explanation.new(nil, self, [event])
|
|
807
|
+
end
|
|
808
|
+
end
|
|
809
|
+
def static?(task)
|
|
810
|
+
event = task.event(event_name)
|
|
811
|
+
evaluate(task) || event.unreachable?
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
def never
|
|
815
|
+
Never.new(self)
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def from_now
|
|
819
|
+
@deadline = Time.now
|
|
820
|
+
self
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
def not_followed_by(event)
|
|
824
|
+
NotFollowedBy.new(self, event.to_unbound_task_predicate)
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
def followed_by(event)
|
|
828
|
+
FollowedBy.new(self, event.to_unbound_task_predicate)
|
|
829
|
+
end
|
|
830
|
+
|
|
831
|
+
def to_s; "#{event_name}?" end
|
|
832
|
+
end
|
|
833
|
+
end
|
|
834
|
+
end
|
|
835
|
+
|