Модуль:SummaryII/rules

Материал из свободной русской энциклопедии «Традиция»
Перейти к: навигация, поиск
{
   ['a'] = 'Value A (real)',
   ['c'] = 'Value A (real)',
   ['b'] = 'Value B (default)',
   ['e'] = 'Value B (default)',
   ['d'] = 'Value B (default)'

}



local Class 		= require 'Module:Class'.create
local Set			= require 'Module:Set'
local DynamicQueue	= require 'Module:DynamicQueue'
--[[
	A class to represent a processing rule or an initial value.
	
	Dependencies:
		Module:Class
		Module:Set
		Module:DynamicQueue
--]]
local serialise = require 'Module:Test'.serialise
local dbg = ''
local Rule = Class {
	real_input			= {}
  , expected_input_map	= {}
}

-- Constructor:
function Rule:_init (input, func, output)
	self.expected_input	= input or {}
	for index, name in ipairs (self.expected_input) do
		self.expected_input_map [name] = index
		self.real_input [index] = false	-- nufortunately, nil will not work.
	end
	self.func			= func
	self.output_key		= output
end		-- function Rule:_init (input, func, output)

-- < reloaded for DynamicQueue:
function Rule:__lt (comparand)
	return #self.expected_input < #comparand.expected_input
end		-- function Rule:_lt (comparand)

function Rule:feed (key, value)
	local numeric_key = self.expected_input_map [key]
	if key and self.real_input [numeric_key] ~= value or #self.expected_input == 0 then
		-- Recomputation needed:
		if key then
			self.real_input [numeric_key] = value
		end
		local output_value, output_key = self:func (unpack (self.real_input))
		--dbg = dbg .. '\nFed ' .. tostring (key) .. ' = ' .. tostring (value) .. ' to ' .. tostring (self.output_key) .. ' . Output: ' .. tostring (output_value)
		--dbg = dbg .. '\nself.real_input = ' .. serialise (self.real_input)
		self.output_value = output_value
		self.output_key = output_key or self.output_key
		return true
	else
		-- Nothing new:
		return false
	end
end		-- function Rule:feed (key, value)

function Rule:output ()
	return self.output_key, self.output_value
end		-- function Rule:output ()

-- end of class Rule.

--[[
	A class to represent a set of processing rules or initial values.
	
	Dependencies:
		Module:Class
		Module:Set
		Module:SummaryII/Rule
--]]

local RuleSet = Class {
	router	= {}
  , outputs	= {}
  , queue	= DynamicQueue ()
}

function RuleSet:_init ()
end		-- function RuleSet:_init ()

function RuleSet:add (rule)
	-- Enqueue:
	self.queue:put (rule)
	-- Data routing:	
	for _, input in ipairs (rule.expected_input) do
		self.router [input] = self.router [input] or Set ()
		self.router [input]:add (rule)
	end
end		-- function RuleSet:add (rule)

function RuleSet:feed (rule, input_key, input_value)
	--dbg = dbg .. '\nFeeding ' .. tostring (input_key) .. ' = ' .. tostring (input_value) .. ' to ' .. tostring (rule.output_key)
	if rule:feed (input_key, input_value) then
		local output_key, output_value = rule:output ()
		if output_key then
			self.outputs [output_key] = output_value
			local next_rules = self.router [output_key]
			if next_rules then
				for next_rule in next_rules () do
					self:feed (next_rule, output_key, output_value)
				end
			end
		end	-- if output_key
	end	-- if rule:feed (input_key, input_value)
	return output_key, output_value
end		-- function RuleSet:feed (rule, input_key, input_value)

-- Lookd like a coroutine iterator is needed:
function RuleSet:compute_all ()
	for _, rule in self.queue () do -- use DynamicQueue iterator.
		--dbg = dbg .. '\nRuleSet:compute_all (). First iterating priority ' .. tostring (priority) .. '. Rule ' .. rule.output
		self:feed (rule)
	end
	-- What is left is in unbreakable circles.
end		-- function RuleSet:compute_all ()

function RuleSet:output (output_key)
	return self.outputs [output_key]
end		-- function RuleSet:output (output_key)

-- end of class RuleSet.

local p = {}

function p.test (frame)
	
	local functions = {
		pass = function (unused, arg)
			return arg or nil
		end
	  , ['or'] = function (unused, arg1, arg2)
			return arg1 or arg2 or nil
		end
	  , serialise = function (self, ...)
	  		local final = {}
	  		for i, name in ipairs (self.expected_input) do
	  			local val = self.real_input [i]
	  			if val then
	  				final [name] = val
	  			end
	  		end
			return serialise (final)
		end
	}	-- local functions = {...}

	local function factory (input, output, typ)
		local func = functions [typ]
			or function ()
				return typ
			end
		return Rule (input, func, output)
	end		-- local function factory (input, output, typ)

	local rules = {
		--		Input									Output		Rule
		factory (	nil,									'arg_a',	'Value A (real)')
	  , factory (	nil,									'def_a',	'Value A (default)')		
	  , factory (	nil, 									'def_b', 	'Value B (default)')
	  , factory (	{'arg_a', 'def_a'},						'a', 		'or')
	  , factory (	{'arg_b', 'def_b'},						'b', 		'or')	  
	  , factory (	{'arg_a'}, 								'c', 		'pass')
	  , factory (	{'d'}, 									'e', 		'pass')
	  , factory (	{'e', 'b'},								'd', 		'or')
	  , factory (	{'f'}, 									'g', 		'pass')
	  , factory (	{'g'}, 									'f', 		'pass')  
	  , factory (	{'a', 'b', 'c', 'd', 'e', 'f', 'g'},	'res',		'serialise')
	}	-- local rules
	local rule_set = RuleSet ()
	for _, rule in ipairs (rules) do
		rule_set:add (rule)
	end
	rule_set:compute_all ()
	return (rule_set:output ('res') or '') .. '\n<pre>' .. dbg .. '</pre>'
end
return p