1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
local domain = require("clever_f.domain")
local sequence_coordinator = require("clever_f.sequence_coordinator")
local M = {}
local ActionFacade = {}
ActionFacade.__index = ActionFacade
M.ActionFacade = ActionFacade
local facade_records = setmetatable({}, { __mode = "k" })
local function fail(message, level)
error(message, (level or 1) + 1)
end
function ActionFacade.new(options)
if ActionFacade.is(options) then
return options
end
local coordinator
if sequence_coordinator.SequenceCoordinator.is(options) then
coordinator = options
elseif type(options) == "table" then
coordinator = options.coordinator
or options.sequence_coordinator
or sequence_coordinator.new(options)
else
fail("ActionFacade options must be a table", 2)
end
if not sequence_coordinator.SequenceCoordinator.is(coordinator) then
fail("ActionFacade requires a SequenceCoordinator", 2)
end
local facade = setmetatable({}, ActionFacade)
facade_records[facade] = { coordinator = coordinator }
return facade
end
function ActionFacade.is(value)
return type(value) == "table" and facade_records[value] ~= nil
end
function ActionFacade:coordinator()
return facade_records[self].coordinator
end
function ActionFacade:primary(descriptor)
local outcome = self:coordinator():primary(descriptor)
if not domain.ActionOutcome.is(outcome) then
fail("SequenceCoordinator must return an ActionOutcome", 2)
end
return outcome
end
function ActionFacade:invoke_descriptor(value)
local descriptor = sequence_coordinator.validate_primary_descriptor(value)
return self:primary(descriptor)
end
ActionFacade.invoke_primary = ActionFacade.invoke_descriptor
ActionFacade.start = ActionFacade.invoke_descriptor
ActionFacade.FreeForm = ActionFacade.invoke_descriptor
function ActionFacade:start_find_forward()
return self:primary("f")
end
function ActionFacade:start_find_backward()
return self:primary("F")
end
function ActionFacade:start_till_forward()
return self:primary("t")
end
function ActionFacade:start_till_backward()
return self:primary("T")
end
ActionFacade.StartFindForward = ActionFacade.start_find_forward
ActionFacade.StartFindBackward = ActionFacade.start_find_backward
ActionFacade.StartTillForward = ActionFacade.start_till_forward
ActionFacade.StartTillBackward = ActionFacade.start_till_backward
function ActionFacade:reset()
local outcome = self:coordinator():reset()
if not domain.ActionOutcome.is(outcome) then
fail("SequenceCoordinator must return an ActionOutcome", 2)
end
return outcome
end
ActionFacade.Reset = ActionFacade.reset
function ActionFacade:diagnostic_full_reset()
local outcome = self:coordinator():diagnostic_full_reset()
if not domain.ActionOutcome.is(outcome) then
fail("SequenceCoordinator must return an ActionOutcome", 2)
end
return outcome
end
ActionFacade.DiagnosticFullReset = ActionFacade.diagnostic_full_reset
local function explicit_outcome(facade, method_name)
local coordinator = facade:coordinator()
local outcome = coordinator[method_name](coordinator)
if not domain.ActionOutcome.is(outcome) then
fail("SequenceCoordinator must return an ActionOutcome", 3)
end
return outcome
end
function ActionFacade:repeat_same_direction()
return explicit_outcome(self, "repeat_same_direction")
end
function ActionFacade:repeat_opposite_direction()
return explicit_outcome(self, "repeat_opposite_direction")
end
ActionFacade.RepeatSameDirection = ActionFacade.repeat_same_direction
ActionFacade.RepeatOppositeDirection = ActionFacade.repeat_opposite_direction
function M.new(options)
return ActionFacade.new(options)
end
setmetatable(M, {
__call = function(_, options)
return ActionFacade.new(options)
end,
})
return M
|