Для документации этого модуля может быть создана страница Модуль:inflection-test/Документация

-- Inflection v1.5.1
-- 2015-05-31

local export = {}
local data
local base
local args
local forms
local affixes

-- TODO: verdict.class_names (если надо несколько классов сразу)

-- Функция-утилита для копирования таблицы
local function clone(original)
    local copy = {}
    for key, value in pairs(original) do
        copy[key] = value
    end
    return copy
end

-- Функция для получения текущего PAGENAME и его окружения
local function get_base()
	local PAGENAME = mw.title.getCurrentTitle().text
	local SUBPAGENAME = mw.title.getCurrentTitle().subpageText
	local NAMESPACE = mw.title.getCurrentTitle().nsText
	
	if NAMESPACE == 'Участник' then
		return SUBPAGENAME
	end
	return PAGENAME
end

-- Функция для загрузки соответствующего дата-модуля
local function load_data(frame)
	local data_name = frame.args['type']
	if data_name == '' then
		return 'Ошибка в вызове модуля [[Module:inflection|inflection]]: Не указан дата-модуль.'
	end
	return mw.loadData("Module:inflection/data/" .. data_name);
end

-- Функция для получения значения аргумента переданного в модуль через шаблон
local function get_arg_value(arg_name)
	local arg_value = ''
	if args[arg_name] then
		arg_value = args[arg_name]
	end
	return arg_value
end

-- Функция для получения значения из affixes
local function get_affix_value(name)
	local value = ''
	if affixes[name] then
		value = affixes[name]
	end
	return value
end

local function apply_affixes(value)
	for affix_key, affix_value in pairs(affixes) do
		value = value:gsub("%<" .. affix_key .. "%>", affix_value)
	end
	return value
end

local function apply_forms(value)  -- TODO: join with function `apply_affixes`
	for form_key, form_value in pairs(forms) do
		value = value:gsub("%<" .. form_key .. "%>", form_value)
	end
	return value
end

-- Проверочная функция (используется в conditions) 
-- Определяет соответствие для последней и предпоследней буквы базового слова
local function check_last(param_name, param_value)
	-- помещаем строку в таблицу, если нужно:
	if type(param_value) == 'string' then
		param_value = {param_value}
	end
	-- проверяем все значения:
	if param_name:match("_NOT$") ~= nil then
		for j, value in pairs(param_value) do
			if param_name == 'last_NOT' and base:match(value .. "$") ~= nil then
				return false
			elseif param_name == 'pre_last_NOT' and base:match(value .. ".$") ~= nil then
				return false
			end
		end
		return true
	else
		for j, value in pairs(param_value) do
			if param_name == 'last' and base:match(value .. "$") ~= nil then
				return true
			elseif param_name == 'pre_last' and base:match(value .. ".$") ~= nil then
				return true
			end
		end
		return false
	end
end

-- Проверочная функция (используется в conditions) 
-- Проверяет соответствие для значения аргумента (переданного через шаблон), либо переменной из affixes
local function check_var(param_name, param_value)
	local NOT = false
	local var_name
	if param_name:match("_NOT$") ~= nil then
		NOT = true
		param_name = param_name:sub(1, -5)
		-- mw.log(param_name)
	end
	if param_name == 'arg' or param_name == 'var' then  -- arg = {'имя', значения}
		var_name = param_value[1]
		param_value = param_value[2]
	else
		var_name = param_name:sub(5)  -- arg_имя = значения
		param_name = param_name:sub(1, 3)
	end
	mw.log('--------')
	mw.log('param_name = ' .. param_name)
	mw.log('var_name = ' .. var_name)
	mw.log('NOT = ', NOT)
	-- помещаем строку в таблицу, если нужно:
	if type(param_value) == 'string' then
		param_value = {param_value}
	end
	-- получаем значение аргумента, переданного в шаблон:
	local var_value = ''
	if param_name == 'arg' then
		var_value = get_arg_value(var_name)
		mw.log('arg_value = ' .. var_value)
	elseif param_name == 'var' then
		var_value = get_affix_value(var_name)
		mw.log('var_value = ' .. var_value)
	end
	mw.log('--------')
	-- проверяем все значения:
	if NOT then
		for j, value in pairs(param_value) do
			if value == var_value then
				return false
			end
		end
		return true
	else
		for j, value in pairs(param_value) do
			if value == var_value then
				return true
			end
		end
		return false
	end
end

-- Функция для проверки правильности одного элемента condition (условие)
local function check_condition(condition)
	for param_name, param_value in pairs(condition) do
		-- выбираем проверочную функцию:
		local check_func = nil
		-- if param_name:match("^(pre_)?last(_NOT)?$") ~= nil then
		if param_name == 'last' or param_name == 'pre_last' or param_name == 'last_NOT' or param_name == 'pre_last_NOT' then
			check_func = check_last
		elseif param_name:match("^arg") ~= nil or param_name:match("^var") ~= nil then
			check_func = check_var
		end
		-- запускаем проверочную функцию:
		if check_func ~= nil then
			if check_func(param_name, param_value) == false then
				return false  -- условие не выполняется
			end
		end
	end
	return true  -- условие выполняется
end

-- Функция для обработки секции actions (действия), которая может размещаться в секции conditions (условия)
local function process_action(action_params)
	local command = action_params[1]
	if command == 'set' then
		local var_name = action_params[2]
		local var_value = action_params[3]
		if type(var_value) == 'string' then
			affixes[var_name] = apply_affixes(var_value)
		elseif type(var_value) == 'table' then
			affixes[var_name] = process_action(var_value)
		end
	elseif command == 'replace' then
		local var_name = action_params[2]
		local pattern = action_params[3]
		local replace = action_params[4]
		local var_value = affixes[var_name]
		return var_value:gsub(pattern, replace)
	elseif command == 'substring' then
		local var_name = action_params[2]
		local from = action_params[3]
		local to = action_params[4]
		local var_value = affixes[var_name]
		return var_value:sub(from, to)
	end
end

-- Функция для обработки секции confitions (условия)
local function process_conditions()
	local conditions = data['conditions']
	local class_names = {'common'}
	for i, condition in pairs(conditions) do
		local condition_satisfied = check_condition(condition)
		if condition_satisfied then
			mw.log('condition #' .. i .. ' satisfied')
			if condition['verdict'] then
				verdict = condition['verdict']
				table.insert(class_names, verdict['class_name']) 
			end
			if condition['actions'] then
				for j, action_params in pairs(condition['actions']) do
					process_action(action_params)
				end
			end
		end
	end	
	return class_names
end

-- Функция для обработки секции classes (классы)
-- Здесь происходит генерирование словоформ
local function process_classes(class_names)
	local all_classes = data['classes']
	forms = {}
	for i, class_name in pairs(class_names) do
		for form_name, form_value in pairs(all_classes[class_name]) do
			forms[form_name] = apply_forms(apply_affixes(form_value))
		end
	end
	return forms
end

-- Функция для обработки секции utils (утилиты)
-- Это пока только пустая заготовка
local function process_utils()
	local utils = data['utils']
	-- local u = require('Module:inflection/utils/reduce-three-letters')
	-- return "Hello, world!" .. u.process()
end

-- Главная фукция, которая вызывается в модуле.
function export.get(frame)
	data = load_data(frame)
	base = get_base()
	mw.log(base)
	if base:match('^[A-Za-z]') == nil then  -- todo: проверять весь алфавит из модуля language
		return ''
	end
	args = frame:getParent().args
	mw.log(args['st'])
	mw.log(args['тип'])
	mw.log(args['type1'])
	
	affixes = clone(data['affixes'])
	affixes['base'] = base
	local class_names = process_conditions()
	process_classes(class_names)
	process_utils()  -- todo
	mw.log(forms['type_expected'])
	return frame:expandTemplate{title=data['template'], args=forms}
end

return export