105 lines
2.1 KiB
Lua
105 lines
2.1 KiB
Lua
local M = {}
|
|
|
|
local stateMeta
|
|
|
|
local function are_both_states(a, b)
|
|
return a.is_state and b.is_state
|
|
end
|
|
|
|
stateMeta = {
|
|
__tostring = function(v)
|
|
return v.name
|
|
end,
|
|
__le = function(self, other)
|
|
if not are_both_states(self, other) then
|
|
return false
|
|
end
|
|
return self.idx <= other.idx
|
|
end,
|
|
__lt = function(self, other)
|
|
if not are_both_states(self, other) then
|
|
return false
|
|
end
|
|
return self.idx < other.idx
|
|
end,
|
|
__index = function(self, name)
|
|
if name == 'is_state' then
|
|
return true
|
|
end
|
|
end
|
|
}
|
|
|
|
function M.build_states(defs)
|
|
local states = {}
|
|
for i, name in ipairs(defs) do
|
|
local state = setmetatable({ idx = i, name = name }, stateMeta)
|
|
states[i] = state
|
|
states[name] = state
|
|
end
|
|
return states
|
|
end
|
|
|
|
local SM = {}
|
|
|
|
local function empty_fn()
|
|
end
|
|
|
|
function SM:run_enter_state(state)
|
|
local enter_fn = self.defs.enter and self.defs.enter[state] or empty_fn
|
|
enter_fn(self.state)
|
|
end
|
|
|
|
function SM:run_exit_state(state)
|
|
local exit_fn = self.defs.exit and self.defs.exit[state] or empty_fn
|
|
exit_fn(self.state)
|
|
end
|
|
|
|
local function wrap_state_array(val)
|
|
return val.is_state and { val } or val
|
|
end
|
|
|
|
local function canonicalize_event(event)
|
|
return {
|
|
from = wrap_state_array(event.from),
|
|
to = event.to,
|
|
transition = event.transition or function() end,
|
|
}
|
|
end
|
|
|
|
function M.build(states, defs)
|
|
local machine = {
|
|
state = states[1],
|
|
defs = defs,
|
|
}
|
|
local prototype = {}
|
|
|
|
for name, infos in pairs(defs.events) do
|
|
local event = canonicalize_event(infos)
|
|
prototype[name] = function(self)
|
|
if not vim.list_contains(event.from, self.state) then
|
|
return false
|
|
end
|
|
local previous = self.state
|
|
self:run_exit_state(previous)
|
|
self.state = event.to
|
|
event.transition(previous, self.state)
|
|
self:run_enter_state(self.state)
|
|
return true
|
|
end
|
|
end
|
|
|
|
local ret = setmetatable(machine, { __index = vim.tbl_extend('error', SM, prototype)})
|
|
ret:run_enter_state(states[1])
|
|
return ret
|
|
end
|
|
|
|
local State = M.build_states {
|
|
'NotLoaded',
|
|
'Shimed',
|
|
'Inited',
|
|
'Imported',
|
|
'Loaded',
|
|
}
|
|
|
|
return M
|