Module:Dni-numerals

From Guild of Archivists

Documentation for this module may be created at Module:Dni-numerals/doc

--
-- This module implements various functions related to dealing with D'ni numerals.
--
-- Exported functions for use in pages:
-- * number_to_dni_string(number)
--     Converts a number to the corresponding dnifont string that would display the number in D'ni when wrapped in a 'dni' element.
-- * number_to_dni_element(number)
--     Converts a number to the corresponding dnifont string wrapped in 'dni' tags to create a 'dni' element.
--
-- Exported functions for use in other modules:
-- * _number_to_dni_digits(number)
--     Converts a number to a table of strings representing the corresponding dnifont digits
-- * _number_to_dni_string(number)
--     Converts a number to the corresponding dnifont string
--

local module = {}

-- A lookup table mapping numbers to
-- their corresponding dnifont characters.
local lookup_table =
{
	[0] = "0", [1] = "1", [2] = "2", [3] = "3", [4] = "4",
	[5] = "5", [6] = "6", [7] = "7", [8] = "8", [9] = "9",
	[10] = ")", [11] = "!", [12] = "@", [13] = "#", [14] = "$",
	[15] = "%", [16] = "^", [17] = "&", [18] = "*", [19] = "(",
	[20] = "[", [21] = "]", [22] = "\\", [23] = "{", [24] = "}",
	[25] = "|",
}

-- Converts a number to a table containing
-- the digits of a dnifont string
local function _number_to_dni_digits(number)
	-- If the number is exactly 0, exit early
	if number == 0 then return { "0" } end
	
	-- If the number is exactly 25,
	-- return the special 25 digit.
	if number == 25 then return { "|" } end
	
	-- Cache some repeatedly used functions
	-- to avoid repetative table lookup.
	local floor = math.floor
	local insert = table.insert
	
	-- Create a table to store the individual
	-- digits of the resulting string.
	local digits = {}
	
	-- Repeat the following
	repeat
		-- Take the remainder of division by 25
		local result = (number % 25)
		
		-- Use the remainder to select the appropriate digit
		local digit = lookup_table[result]
		
		-- Insert the digit into the start of the table
		insert(digits, 1, digit)
		
		-- Divide the number by 25 to begin work on the next digit
		number = floor(number / 25)
		
	-- If the result of the division was 0, the work is done,
	-- else, repeat the process until no more digits remain.
	until number == 0
	
	-- Return the table containing the digits
	return digits
end

-- Converts a number to a dnifont string
local function _number_to_dni_string(number)
		-- If the number is exactly 0, exit early
	if number == 0 then return "0" end
		
	-- If the number is exactly 25,
	-- return the special 25 digit.
	if number == 25 then return "|" end
	
	-- Else, defer to _number_to_dni_digits
	return table.concat(_number_to_dni_digits(number))
end

-- Converts a number to a dnifont string when called from within a page
function module.number_to_dni_string(frame)
	-- If the frame wasn't provided with a proper argument, throw an error
	if frame.args[1] == nil then error "Expected a non-nil argument." end
	
	-- Attempt to convert the first parameter to a number
	local number = tonumber(frame.args[1])
	
	-- Pass the converted parameter to the conversion function.
	return _number_to_dni_string(number)
end

-- Converts a number to a dni element when called from within a page
function module.number_to_dni_element(frame)
	-- If the frame wasn't provided with a proper argument, throw an error
	if frame.args[1] == nil then error "Expected a non-nil argument." end
	
	-- Attempt to convert the first parameter to a number
	local number = tonumber(frame.args[1])
	
	-- Pass the converted parameter to the conversion function.
	local digits = _number_to_dni_digits(tonumber(frame.args[1]))
	
	-- Prepend an open tag
	table.insert(digits, 1, "<dni>")
	
	-- Append a close tag
	table.insert(digits, "</dni>")
	
	-- Return the concatenated result
	return table.concat(digits)
end

-- Provide local functions for export,
-- with the intent that they be called only by other modules.
module._number_to_dni_digits = _number_to_dni_digits
module._number_to_dni_string = _number_to_dni_string

return module