224 lines
7.2 KiB
Lua
Executable File
224 lines
7.2 KiB
Lua
Executable File
--------------------------------------------------------------------------------
|
|
---------------------- ## ##### ##### ###### -----------------------
|
|
---------------------- ## ## ## ## ## ## ## -----------------------
|
|
---------------------- ## ## ## ## ## ###### -----------------------
|
|
---------------------- ## ## ## ## ## ## -----------------------
|
|
---------------------- ###### ##### ##### ## -----------------------
|
|
---------------------- -----------------------
|
|
----------------------- Lua Object-Oriented Programming ------------------------
|
|
--------------------------------------------------------------------------------
|
|
-- Project: LOOP - Lua Object-Oriented Programming --
|
|
-- Release: 2.3 beta --
|
|
-- Title : Component Model with Dynamically Adaptable Containers --
|
|
-- Author : Renato Maia <maia@inf.puc-rio.br> --
|
|
--------------------------------------------------------------------------------
|
|
-- Exported API: --
|
|
-- Template --
|
|
-- factoryof(component) --
|
|
-- templateof(factory|component) --
|
|
-- ports(template) --
|
|
-- segmentof(portname, component) --
|
|
-- addport(template|factory|component, portname, porttype [, portimpl]) --
|
|
-- removeport(template|factory|component, portname) --
|
|
--------------------------------------------------------------------------------
|
|
|
|
local next = next
|
|
local rawget = rawget
|
|
local select = select
|
|
|
|
local oo = require "loop.cached"
|
|
local base = require "loop.component.contained"
|
|
|
|
module "loop.component.dynamic"
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
local WeakTable = oo.class{ __mode = "k" }
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
local DynamicPort = oo.class()
|
|
|
|
function DynamicPort:__call(state, name, ...)
|
|
if self.class then
|
|
state[name] = self.class(state[name], state.__component)
|
|
end
|
|
return self.port(state, name, ...)
|
|
end
|
|
|
|
function DynamicPort:__tostring()
|
|
return self.name
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
local InternalState = oo.class()
|
|
|
|
function InternalState:__index(name)
|
|
self = self.__container
|
|
local state = self.__state
|
|
local port, manager = state[name], self[name]
|
|
if manager == nil then
|
|
local factory = state.__factory
|
|
local class = factory[name]
|
|
if oo.classof(class) == DynamicPort then
|
|
local context = self.__internal
|
|
self[class] = class(state, class, context)
|
|
port, manager = state[class], self[class]
|
|
factory:__setcontext(port, context)
|
|
end
|
|
end
|
|
return port, manager
|
|
end
|
|
|
|
function InternalState:__newindex(name, value)
|
|
self = self.__container
|
|
local state = self.__state
|
|
local manager = self[name]
|
|
if manager == nil then
|
|
local factory = state.__factory
|
|
local class = factory[name]
|
|
if oo.classof(class) == DynamicPort then
|
|
local context = self.__internal
|
|
self[class] = class(state, class, context)
|
|
manager = self[class]
|
|
factory:__setcontext(state[class], context)
|
|
end
|
|
end
|
|
if manager and manager.__bind then
|
|
manager:__bind(value)
|
|
elseif manager ~= nil then
|
|
state[name] = value
|
|
else
|
|
state.__component[name] = value
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
local ExternalState = oo.class({}, InternalState)
|
|
|
|
function ExternalState:__index(name)
|
|
local port, manager = oo.superclass(ExternalState).__index(self, name)
|
|
if port and manager then
|
|
return rawget(manager, "__external") or manager
|
|
else
|
|
local component = self.__container.__state.__component
|
|
return base.delegate(port or component[name], component)
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
BaseTemplate = oo.class({}, base.BaseTemplate)
|
|
|
|
function BaseTemplate:__container(comp)
|
|
local container = WeakTable(base.BaseTemplate.__container(self, comp))
|
|
container.__state = WeakTable(container.__state)
|
|
container.__internal = InternalState{ __container = container }
|
|
container.__external = ExternalState{ __container = container }
|
|
return container
|
|
end
|
|
|
|
function Template(template, ...)
|
|
return oo.class(template, BaseTemplate, ...)
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
factoryof = base.factoryof
|
|
templateof = base.templateof
|
|
|
|
local function portiterator(container, name)
|
|
local factory = container.__state.__factory
|
|
local port = factory[name]
|
|
if oo.classof(port) == DynamicPort then
|
|
name = port
|
|
end
|
|
repeat
|
|
name = next(container, name)
|
|
if name == nil then
|
|
return nil
|
|
elseif oo.classof(name) == DynamicPort then
|
|
return name.name, name.port
|
|
end
|
|
until name:find("^%a[%w_]*$")
|
|
return name, oo.classof(factory)[name]
|
|
end
|
|
|
|
function ports(component)
|
|
local container = component.__container
|
|
if container
|
|
then return portiterator, container
|
|
else return base.port(component)
|
|
end
|
|
end
|
|
|
|
function segmentof(comp, name)
|
|
local state = comp.container.__state
|
|
local port = state.__factory[name]
|
|
if oo.classof(port) == DynamicPort then
|
|
name = port
|
|
end
|
|
return state[port]
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function addport(scope, name, port, class)
|
|
if oo.isclass(scope) or oo.instanceof(scope, BaseTemplate) then
|
|
scope[name] = DynamicPort{
|
|
name = name,
|
|
port = port,
|
|
class = class,
|
|
}
|
|
else
|
|
base.addport(scope, name, port, class)
|
|
end
|
|
end
|
|
|
|
function removeport(scope, name)
|
|
if oo.isclass(scope) or oo.instanceof(scope, BaseTemplate) then
|
|
scope[name] = nil
|
|
else
|
|
base.removeport(scope, name)
|
|
end
|
|
end
|
|
|
|
--[[----------------------------------------------------------------------------
|
|
MyCompTemplate = comp.Template{
|
|
[<portname>] = <PortClass>,
|
|
[<portname>] = <PortClass>,
|
|
[<portname>] = <PortClass>,
|
|
}
|
|
|
|
MyContainer = WeakKeyTable{
|
|
__external = Handler{ <container> },
|
|
__internal = Context{ <container> },
|
|
__state = WeakKeyTable{
|
|
<componentimpl>,
|
|
[<portname>] = <portimpl>,
|
|
[<portname>] = <portimpl>,
|
|
[<dynaport>] = <portimpl>,
|
|
},
|
|
__factory = {
|
|
[<portname>] = <portclass>,
|
|
[<portname>] = <portclass>,
|
|
[<portname>] = <dynaport>,
|
|
},
|
|
[<portname>] = <portmanager>,
|
|
[<portname>] = <portmanager>,
|
|
[<dynaport>] = <portmanager>,
|
|
}
|
|
|
|
EMPTY Internal Self | EMPTY Internal Self
|
|
Facet nil wrapper | Facet nil nil
|
|
Receptacle nil wrapper | Receptacle nil nil
|
|
Multiple multiple wrapper | Multiple multiple nil
|
|
|
|
|
FILLED Internal Self | FILLED Internal Self
|
|
Facet port wrapper | Facet port nil
|
|
Receptacle wrapper wrapper | Receptacle port nil
|
|
Multiple multiple wrapper | Multiple multiple nil
|
|
----------------------------------------------------------------------------]]--
|