Module:Scribunto - Wiktionary, the free dictionary
From Wiktionary, the free dictionary
- The following documentation is located at Module:Scribunto/documentation. [edit]
- Useful links: subpage list • links • transclusions • testcases • sandbox
This module provides some utility functions for emulating certain parts of the inner-workings of Scribunto, as well as the underlying PHP-based MediaWiki platform.
They are used to support other modules that deal with template parameters or wikitext parsing (e.g. for template expansion).
Functions
export.php_htmlspecialchars
function export.php_htmlspecialchars(str, quotes)
Lua equivalent of PHP's htmlspecialchars($string)
, which converts the characters &"'<>
to HTML entities.
If the quotes
flag is set to "compat"
, then '
will not be converted, and if it is set to "noquotes"
, then neither "
nor '
will be converted.
export.php_string_equals
function export.php_string_equals(str1, str2)
Lua equivalent of PHP's ==
operator for strings.
export.php_trim
function export.php_trim(str)
Lua equivalent of PHP's trim($string)
, which trims "\0"
, "\t"
, "\n"
, "\v"
, "\r"
and " "
. This is useful when dealing with template parameters, since the native parser trims them like this.
export.scribunto_parameter_key
function export.scribunto_parameter_key(key, no_trim)
Takes a template or module parameter name as either a string or number, and returns the Scribunto-normalized form (i.e. the key that that parameter would have in a frame.args
table). For example, "1"
(a string) is normalized to 1
(a number), " foo "
is normalized to "foo"
, and 1.5
(a number) is normalized to "1.5"
(a string). Inputs which cannot be normalized (e.g. booleans) return nil
.
Strings are trimmed with export.php_trim
, unless the no_trim
flag is set. If it is, then string parameters are not trimmed, but strings may still be converted to numbers if they do not contain whitespace; this is necessary when normalizing keys into the form received by PHP during callbacks, before any trimming occurs (e.g. in the table of arguments when calling frame:expandTemplates()
).
After trimming (if applicable), keys are then converted to numbers if all of the following are true:
- They are integers; i.e. no decimals or leading zeroes (e.g.
"2"
, but not"2.0"
or"02"
). - They are ≤ 253 and ≥ -253.
- There is no leading sign unless < 0 (e.g.
"2"
or"-2"
, but not"+2"
or"-0"
). - They contain no leading or trailing whitespace (which may be present when the
no_trim
flag is set).
Numbers are converted to strings if either:
- They are not integers (e.g.
1.5
). - They are > 253 or < -253.
When converted to strings, integers ≤ 263 and ≥ -263 are formatted as integers (i.e. all digits are given), which is the range of PHP's integer precision, though the actual output may be imprecise since Lua's integer precision is > 253 to < -253. All other numbers use the standard formatting output by tostring()
.
export.scribunto_parameter_value
function export.scribunto_parameter_value(value, named)
Takes a template or module parameter value as either a string, number or boolean, and returns the Scribunto-normalized form (i.e. the value that that parameter would have in a frame.args
table), which is always a string. For example, "foo"
remains the same, 2
(a number) is normalized to "2"
(a string), true
is normalized to "1"
, and false
is normalized to ""
. Inputs which cannot be normalized (e.g. tables) return nil
.
By default, returned values are not trimmed, which matches the treatment of unnamed parameters (e.g. bar
in {{foo|bar}}
). If the named
flag is set, then returned values will be trimmed, which matches the treatment of named parameters (e.g. baz
in {{foo|bar=baz}}
).
local export = {} local math_module = "Module:math" local dump = mw.dumpObject local format = string.format local gsub = string.gsub local match = string.match local php_trim -- defined below local sub = string.sub local tonumber = tonumber local tostring = tostring local type = type do local php_htmlspecialchars_data local function get_php_htmlspecialchars_data() php_htmlspecialchars_data, get_php_htmlspecialchars_data = { ["\""] = """, ["&"] = "&", ["'"] = "'", ["<"] = "<", [">"] = ">", }, nil return php_htmlspecialchars_data end --[==[Lua equivalent of PHP's {{code|php|htmlspecialchars($string)}}, which converts the characters `&"'<>` to HTML entities. If the `quotes` flag is set to {"compat"}, then `'` will not be converted, and if it is set to {"noquotes"}, then neither `"` nor `'` will be converted.]==] function export.php_htmlspecialchars(str, quotes) if quotes == nil or quotes == "quotes" then quotes = "'\"" elseif quotes == "compat" then quotes = "\"" elseif quotes == "noquotes" then quotes = "" else local quotes_type = type(quotes) error('`quotes` must be "quotes", "compat", "noquotes" or nil; received ' .. (quotes_type == "string" and dump(quotes) or "a " .. quotes_type)) end return (gsub(str, "[&<>" .. quotes .. "]", php_htmlspecialchars_data or get_php_htmlspecialchars_data())) end end do local function tonumber_extended(...) tonumber_extended = require(math_module).tonumber_extended return tonumber_extended(...) end -- Normalizes a string for use in comparisons which emulate PHP's equals -- operator, which coerces certain strings to numbers: those within the -- range -2^63 to 2^63 - 1 which don't have decimal points or exponents are -- coerced to integers, while any others are coerced to doubles if possible; -- otherwise, they remain as strings. PHP and Lua have the same precision -- for doubles, but Lua's integer precision range is -2^53 + 1 to 2^53 - 1. -- Any integers within Lua's precision, as well as all doubles, are simply -- coerced to numbers, but PHP integers outside of Lua's precision are -- emulated as normalized strings, with leading 0s and any + sign removed. -- The `not_long` flag is used for the second comparator if the first did -- not get normalized to a long integer, as PHP will only coerce strings to -- integers if it's possible for both comparators. local function php_normalize_string(str, not_long) local num = tonumber_extended(str, nil, true) -- Must be a number that isn't ±infinity, NaN or hexadecimal. if not num or match(str, "^%s*[+-]?0[xX]()") then return str -- If `not_long` is set or `num` is within Lua's precision, return as a -- number. elseif not_long or num < 9007199254740992 and num > -9007199254740992 then return num, "number" end -- Check if it could be a long integer, and return as a double if not. local sign, str_no_0 = match(str, "^%s*([+-]?)0*(%d+)$") if not str_no_0 then return num, "number" end -- Otherwise, check if it's a long integer. 2^63 is 9223372036854775808, -- so slice off the last 15 digits and deal with the two parts -- separately. If the integer value would be too high/low, return as a -- string. local high = tonumber(sub(str_no_0, 1, -16)) if high > 9223 then return str elseif high == 9223 then local low = tonumber(sub(str_no_0, -15)) -- Range is -2^63 to 2^63 - 1 (not symmetrical). if low > 372036854775808 or low == 372036854775808 and sign ~= "-" then return str end end return (sign == "+" and "" or sign) .. str_no_0, "long integer", num end --[==[Lua equivalent of PHP's {{code|php|===}} operator for strings.]==] function export.php_string_equals(str1, str2) if str1 == str2 then return true end local str1, str1_type, str1_num = php_normalize_string(str1) if str1 == str2 then return true elseif str1_type == "long integer" then local str2, str2_type = php_normalize_string(str2) return str2 == (str2_type == "number" and str1_num or str1) elseif str1_type == "number" then return str1 == php_normalize_string(str2, true) end return false end end --[==[Lua equivalent of PHP's {{code|php|trim($string)}}, which trims {"\0"}, {"\t"}, {"\n"}, {"\v"}, {"\r"} and {" "}. This is useful when dealing with template parameters, since the native parser trims them like this.]==] function export.php_trim(str) return match(str, "%f[^%z\t\n\v\r ].*%f[%z\t\n\v\r ]") or "" end php_trim = export.php_trim --[==[Takes a template or module parameter name as either a string or number, and returns the Scribunto-normalized form (i.e. the key that that parameter would have in a {frame.args} table). For example, {"1"} (a string) is normalized to {1} (a number), {" foo "} is normalized to {"foo"}, and {1.5} (a number) is normalized to {"1.5"} (a string). Inputs which cannot be normalized (e.g. booleans) return {nil}. Strings are trimmed with {export.php_trim}, unless the `no_trim` flag is set. If it is, then string parameters are not trimmed, but strings may still be converted to numbers if they do not contain whitespace; this is necessary when normalizing keys into the form received by PHP during callbacks, before any trimming occurs (e.g. in the table of arguments when calling {frame:expandTemplates()}). After trimming (if applicable), keys are then converted to numbers if '''all''' of the following are true: # They are integers; i.e. no decimals or leading zeroes (e.g. {"2"}, but not {"2.0"} or {"02"}). # They are ≤ 2{{sup|53}} and ≥ -2{{sup|53}}. # There is no leading sign unless < 0 (e.g. {"2"} or {"-2"}, but not {"+2"} or {"-0"}). # They contain no leading or trailing whitespace (which may be present when the `no_trim` flag is set). Numbers are converted to strings if '''either''': # They are not integers (e.g. {1.5}). # They are > 2{{sup|53}} or < -2{{sup|53}}. When converted to strings, integers ≤ 2{{sup|63}} and ≥ -2{{sup|63}} are formatted as integers (i.e. all digits are given), which is the range of PHP's integer precision, though the actual output may be imprecise since Lua's integer precision is > 2{{sup|53}} to < -2{{sup|53}}. All other numbers use the standard formatting output by {tostring()}.]==] function export.scribunto_parameter_key(key, no_trim) local key_type = type(key) if key_type == "string" then if not no_trim then key = php_trim(key) end if match(key, "^()-?[1-9]%d*$") then local num = tonumber(key) -- Lua integers are only precise to 2^53 - 1, so specifically check -- for 2^53 and -2^53 as strings, since a numerical comparison won't -- work as it can't distinguish 2^53 from 2^53 + 1. return ( num <= 9007199254740991 and num >= -9007199254740991 or key == "9007199254740992" or key == "-9007199254740992" ) and num or key end return key == "0" and 0 or key elseif key_type == "number" then -- No special handling needed for inf or NaN. return key % 1 == 0 and ( key <= 9007199254740992 and key >= -9007199254740992 and key or key <= 9223372036854775808 and key >= -9223372036854775808 and format("%d", key) ) or tostring(key) end return nil end --[==[Takes a template or module parameter value as either a string, number or boolean, and returns the Scribunto-normalized form (i.e. the value that that parameter would have in a {frame.args} table), which is always a string. For example, {"foo"} remains the same, {2} (a number) is normalized to {"2"} (a string), {true} is normalized to {"1"}, and {false} is normalized to {""}. Inputs which cannot be normalized (e.g. tables) return {nil}. By default, returned values are not trimmed, which matches the treatment of unnamed parameters (e.g. `bar` in {{tl|<nowiki/>foo|bar}}). If the `named` flag is set, then returned values will be trimmed, which matches the treatment of named parameters (e.g. `baz` in {{tl|<nowiki/>foo|bar=baz}}).]==] function export.scribunto_parameter_value(value, named) local value_type = type(value) if value_type == "string" then return named and php_trim(value) or value elseif value_type == "number" then return tostring(value) elseif value_type == "boolean" then return value and "1" or "" end return nil end return export