222 lines
6.5 KiB
Lua
Executable File
222 lines
6.5 KiB
Lua
Executable File
--------------------------------------------------------------------------------
|
|
---------------------- ## ##### ##### ###### -----------------------
|
|
---------------------- ## ## ## ## ## ## ## -----------------------
|
|
---------------------- ## ## ## ## ## ###### -----------------------
|
|
---------------------- ## ## ## ## ## ## -----------------------
|
|
---------------------- ###### ##### ##### ## -----------------------
|
|
---------------------- -----------------------
|
|
----------------------- Lua Object-Oriented Programming ------------------------
|
|
--------------------------------------------------------------------------------
|
|
-- Project: LOOP - Lua Object-Oriented Programming --
|
|
-- Release: 2.3 beta --
|
|
-- Title : Base Component Model --
|
|
-- Author : Renato Maia <maia@inf.puc-rio.br> --
|
|
--------------------------------------------------------------------------------
|
|
-- Exported API: --
|
|
-- Template --
|
|
-- Facet --
|
|
-- Receptacle --
|
|
-- ListReceptacle --
|
|
-- HashReceptacle --
|
|
-- SetReceptacle --
|
|
-- factoryof(component) --
|
|
-- templateof(factory|component) --
|
|
-- ports(template) --
|
|
-- segmentof(portname, component) --
|
|
--------------------------------------------------------------------------------
|
|
|
|
local next = next
|
|
local pairs = pairs
|
|
local pcall = pcall
|
|
local rawget = rawget
|
|
local rawset = rawset
|
|
local select = select
|
|
local type = type
|
|
|
|
local oo = require "loop.cached"
|
|
|
|
module "loop.component.base"
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
BaseTemplate = oo.class()
|
|
|
|
function BaseTemplate:__call(...)
|
|
return self:__build(self:__new(...))
|
|
end
|
|
|
|
function BaseTemplate:__new(...)
|
|
local comp = self.__component or self[1]
|
|
if comp then
|
|
comp = comp(...)
|
|
comp.__component = comp
|
|
else
|
|
comp = ... or {}
|
|
end
|
|
comp.__factory = self
|
|
for port, class in pairs(self) do
|
|
if type(port) == "string" and port:match("^%a[%w_]*$") then
|
|
comp[port] = class(comp[port], comp)
|
|
end
|
|
end
|
|
return comp
|
|
end
|
|
|
|
local function tryindex(segment) return segment.context end
|
|
function BaseTemplate:__setcontext(segment, context)
|
|
local success, setcontext = pcall(tryindex, segment)
|
|
if success and setcontext ~= nil then
|
|
if type(setcontext) == "function"
|
|
then setcontext(segment, context)
|
|
else segment.context = context
|
|
end
|
|
end
|
|
end
|
|
|
|
function BaseTemplate:__build(segments)
|
|
for port, class in oo.allmembers(oo.classof(self)) do
|
|
if port:match("^%a[%w_]*$") then
|
|
class(segments, port, segments)
|
|
end
|
|
end
|
|
segments.__reference = segments
|
|
for port in pairs(self) do
|
|
if port == 1
|
|
then self:__setcontext(segments.__component, segments)
|
|
else self:__setcontext(segments[port], segments)
|
|
end
|
|
end
|
|
return segments
|
|
end
|
|
|
|
function Template(template, ...)
|
|
if select("#", ...) > 0
|
|
then return oo.class(template, ...)
|
|
else return oo.class(template, BaseTemplate)
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function factoryof(component)
|
|
return component.__factory
|
|
end
|
|
|
|
function templateof(object)
|
|
return oo.classof(factoryof(object) or object)
|
|
end
|
|
|
|
local nextmember
|
|
local function portiterator(state, name)
|
|
local port
|
|
repeat
|
|
name, port = nextmember(state, name)
|
|
if name == nil then return end
|
|
until name:find("^%a")
|
|
return name, port
|
|
end
|
|
function ports(template)
|
|
if not oo.subclassof(template, BaseTemplate) then
|
|
template = templateof(template)
|
|
end
|
|
local state, var
|
|
nextmember, state, var = oo.allmembers(template)
|
|
return portiterator, state, var
|
|
end
|
|
|
|
function segmentof(comp, port)
|
|
return comp[port]
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function addport(comp, name, port, class)
|
|
if class then
|
|
comp[name] = class(comp[name], comp)
|
|
end
|
|
port(comp, name, comp)
|
|
comp.__factory:__setcontext(comp[name], context)
|
|
end
|
|
|
|
function removeport(comp, name)
|
|
comp[name] = nil
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function Facet(segments, name)
|
|
segments[name] = segments[name] or
|
|
segments.__component[name] or
|
|
segments.__component
|
|
return false
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function Receptacle()
|
|
return false
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
MultipleReceptacle = oo.class{
|
|
__all = pairs,
|
|
__hasany = next,
|
|
__get = rawget,
|
|
}
|
|
|
|
function MultipleReceptacle:__init(segments, name)
|
|
local receptacle = oo.rawnew(self, segments[name])
|
|
segments[name] = receptacle
|
|
return receptacle
|
|
end
|
|
|
|
function MultipleReceptacle:__newindex(key, value)
|
|
if value == nil
|
|
then self:__unbind(key)
|
|
else self:__bind(value, key)
|
|
end
|
|
end
|
|
|
|
function MultipleReceptacle:__unbind(key)
|
|
local port = rawget(self, key)
|
|
rawset(self, key, nil)
|
|
return port
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
ListReceptacle = oo.class({}, MultipleReceptacle)
|
|
|
|
function ListReceptacle:__bind(port)
|
|
local index = #self + 1
|
|
rawset(self, index, port)
|
|
return index
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
HashReceptacle = oo.class({}, MultipleReceptacle)
|
|
|
|
function HashReceptacle:__bind(port, key)
|
|
rawset(self, key, port)
|
|
return key
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
SetReceptacle = oo.class({}, MultipleReceptacle)
|
|
|
|
function SetReceptacle:__bind(port)
|
|
rawset(self, port, port)
|
|
return port
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
_M[Facet ] = "Facet"
|
|
_M[Receptacle ] = "Receptacle"
|
|
_M[ListReceptacle] = "ListReceptacle"
|
|
_M[HashReceptacle] = "HashReceptacle"
|
|
_M[SetReceptacle ] = "SetReceptacle"
|