Skip to content

Instantly share code, notes, and snippets.

@vendethiel
Created May 2, 2021 00:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vendethiel/cd8ecd0c42bf99ac4a5ccd4198382991 to your computer and use it in GitHub Desktop.
Save vendethiel/cd8ecd0c42bf99ac4a5ccd4198382991 to your computer and use it in GitHub Desktop.
State machine
package.path = package.path .. ";../?/init.lua;../?.lua"
require "PLoop"(function (_ENV)
class "__State_Machine__" (function(_ENV)
extend "IApplyAttribute"
function ApplyAttribute(self, target, targettype, manager, owner, name, stack)
if manager then
Environment.Apply(manager, function(_ENV)
property "State" { default = self.State }
end)
end
end
property "AttributeTarget" { default = AttributeTargets.Interface + AttributeTargets.Class }
property "State" { }
-- TODO allowed states
end)
class "__State__"(function(_ENV)
extend "IInitAttribute"
function InitDefinition(self, target, targettype, definition, owner, name, stack)
return function (o, ...)
print(o .. " [" .. (o.State or "nil") .. "] --> [" .. (self.To or "nil") .. "]")
if o.State == self.From then
definition(o, ...)
print(" [" .. (o.State or "nil") .. "] --> [" .. (self.To or "nil") .. "]")
o.State = self.To
else
throw("Cannot start with a state [" .. (o.State or "nil") .. "], expected state [" .. (self.From or "nil") .. "]")
end
end
end
property "From" {}
property "To" {}
end)
__State_Machine__{ State = "Start" }
class "MyMachine"(function(_ENV)
__State__{ From = "Start", To = "Stop" }
function SetState()
end
end)
local instance = MyMachine()
print("iz "..instance.State)
MyMachine:SetState()
MyMachine:SetState()
end)
@kurapica
Copy link

kurapica commented May 2, 2021

require "PLoop"(function (_ENV)

  class "__State_Machine__" (function(_ENV)
    extend "IApplyAttribute"

    function ApplyAttribute(self, target, targettype, manager, owner, name, stack)
      -- make the self not the upvalue of the anonymous function, so it can be collcted
      -- but in this example, use self.State is ok, since the anonymous function will also be collcted
      local defaultState = self.State

        Environment.Apply(manager, function(_ENV)
            property "State" { default = defaultState }
        end)
    end

    property "AttributeTarget" { default = AttributeTargets.Interface + AttributeTargets.Class }

    property "State" { }
    -- TODO allowed states
  end)

  class "__State__"(function(_ENV)
    extend "IInitAttribute"


    function InitDefinition(self, target, targettype, definition, owner, name, stack)
      -- Since the anonymous function won't be collcted, don't use self in it, that will make the
      -- attr object can't be collected.
      local from = self.From
      local to = self.To

      return function (self, ...)
        print(tostring(self) .. " [" .. (self.State or "nil") .. "] --> [" .. (to or "nil") .. "]")

        if self.State == from then
          definition(self, ...)

          print(" [" .. (self.State or "nil") .. "] --> [" .. (to or "nil") .. "]")
          self.State = to
        else
          -- Throw will use an object as error, but it can only be catched by a pcall/xpcall,
          -- Here the stack is clear, so, just use the error is ok
          error("Cannot start with a state [" .. (self.State or "nil") .. "], expected state [" .. (from or "nil") .. "]", 2)
        end
      end
    end

    property "From" {}
    property "To" {}
  end)

  __State_Machine__{ State = "Start" }
  class "MyMachine"(function(_ENV)
    __State__{ From = "Start", To = "Stop" }
    function SetState()
    end
  end)

  local instance = MyMachine()
  print("iz "..instance.State)
  instance:SetState()
  instance:SetState()


end)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment