Home
Random
Recent changes
Special pages
Community portal
Preferences
About Stockhub
Disclaimers
Search
User menu
Talk
Contributions
Create account
Log in
Editing
Module:Repr
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
require('strict') local libraryUtil = require("libraryUtil") local checkType = libraryUtil.checkType local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg local defaultOptions = { pretty = false, tabs = true, semicolons = false, spaces = 4, sortKeys = true, depth = 0, } -- Define the reprRecursive variable here so that we can call the reprRecursive -- function from renderSequence and renderKeyValueTable without getting -- "Tried to read nil global reprRecursive" errors. local reprRecursive local luaKeywords = { ["and"] = true, ["break"] = true, ["do"] = true, ["else"] = true, ["elseif"] = true, ["end"] = true, ["false"] = true, ["for"] = true, ["function"] = true, ["if"] = true, ["in"] = true, ["local"] = true, ["nil"] = true, ["not"] = true, ["or"] = true, ["repeat"] = true, ["return"] = true, ["then"] = true, ["true"] = true, ["until"] = true, ["while"] = true, } --[[ -- Whether the given value is a valid Lua identifier (i.e. whether it can be -- used as a variable name.) --]] local function isLuaIdentifier(str) return type(str) == "string" -- Must start with a-z, A-Z or underscore, and can only contain -- a-z, A-Z, 0-9 and underscore and str:find("^[%a_][%a%d_]*$") ~= nil -- Cannot be a Lua keyword and not luaKeywords[str] end --[[ -- Render a string representation. --]] local function renderString(s) return (("%q"):format(s):gsub("\\\n", "\\n")) end --[[ -- Render a number representation. --]] local function renderNumber(n) if n == math.huge then return "math.huge" elseif n == -math.huge then return "-math.huge" else return tostring(n) end end --[[ -- Whether a table has a __tostring metamethod. --]] local function hasTostringMetamethod(t) return getmetatable(t) and type(getmetatable(t).__tostring) == "function" end --[[ -- Pretty print a sequence of string representations. -- This can be made to represent different constructs depending on the values -- of prefix, suffix, and separator. The amount of whitespace is controlled by -- the depth and indent parameters. --]] local function prettyPrintItemsAtDepth(items, prefix, suffix, separator, indent, depth) local whitespaceAtCurrentDepth = "\n" .. indent:rep(depth) local whitespaceAtNextDepth = whitespaceAtCurrentDepth .. indent local ret = {prefix, whitespaceAtNextDepth} local first = items[1] if first ~= nil then table.insert(ret, first) end for i = 2, #items do table.insert(ret, separator) table.insert(ret, whitespaceAtNextDepth) table.insert(ret, items[i]) end table.insert(ret, whitespaceAtCurrentDepth) table.insert(ret, suffix) return table.concat(ret) end --[[ -- Render a sequence of string representations. -- This can be made to represent different constructs depending on the values of -- prefix, suffix and separator. --]] local function renderItems(items, prefix, suffix, separator) return prefix .. table.concat(items, separator .. " ") .. suffix end --[[ -- Render a regular table (a non-cyclic table with no __tostring metamethod). -- This can be a sequence table, a key-value table, or a mix of the two. --]] local function renderNormalTable(t, context, depth) local items = {} -- Render the items in the sequence part local seen = {} for i, value in ipairs(t) do table.insert(items, reprRecursive(t[i], context, depth + 1)) seen[i] = true end -- Render the items in the key-value part local keyOrder = {} local keyValueStrings = {} for k, v in pairs(t) do if not seen[k] then local kStr = isLuaIdentifier(k) and k or ("[" .. reprRecursive(k, context, depth + 1) .. "]") local vStr = reprRecursive(v, context, depth + 1) table.insert(keyOrder, kStr) keyValueStrings[kStr] = vStr end end if context.sortKeys then table.sort(keyOrder) end for _, kStr in ipairs(keyOrder) do table.insert(items, string.format("%s = %s", kStr, keyValueStrings[kStr])) end -- Render the table structure local prefix = "{" local suffix = "}" if context.pretty then return prettyPrintItemsAtDepth( items, prefix, suffix, context.separator, context.indent, depth ) else return renderItems(items, prefix, suffix, context.separator) end end --[[ -- Render the given table. -- As well as rendering regular tables, this function also renders cyclic tables -- and tables with a __tostring metamethod. --]] local function renderTable(t, context, depth) if hasTostringMetamethod(t) then return tostring(t) elseif context.shown[t] then return "{CYCLIC}" end context.shown[t] = true local result = renderNormalTable(t, context, depth) context.shown[t] = false return result end --[[ -- Recursively render a string representation of the given value. --]] function reprRecursive(value, context, depth) if value == nil then return "nil" end local valueType = type(value) if valueType == "boolean" then return tostring(value) elseif valueType == "number" then return renderNumber(value) elseif valueType == "string" then return renderString(value) elseif valueType == "table" then return renderTable(value, context, depth) else return "<" .. valueType .. ">" end end --[[ -- Normalize a table of options passed by the user. -- Any values not specified will be assigned default values. --]] local function normalizeOptions(options) options = options or {} local ret = {} for option, defaultValue in pairs(defaultOptions) do local value = options[option] if value ~= nil then if type(value) == type(defaultValue) then ret[option] = value else error( string.format( 'Invalid type for option "%s" (expected %s, received %s)', option, type(defaultValue), type(value) ), 3 ) end else ret[option] = defaultValue end end return ret end --[[ -- Get the indent from the options table. --]] local function getIndent(options) if options.tabs then return "\t" else return string.rep(" ", options.spaces) end end --[[ -- Render a string representation of the given value. --]] local function repr(value, options) checkType("repr", 2, options, "table", true) options = normalizeOptions(options) local context = {} context.pretty = options.pretty if context.pretty then context.indent = getIndent(options) else context.indent = "" end if options.semicolons then context.separator = ";" else context.separator = "," end context.sortKeys = options.sortKeys context.shown = {} local depth = options.depth return reprRecursive(value, context, depth) end --[[ -- Render a string representation of the given function invocation. --]] local function invocationRepr(keywordArgs) checkType("invocationRepr", 1, keywordArgs, "table") checkTypeForNamedArg("invocationRepr", "funcName", keywordArgs.funcName, "string") checkTypeForNamedArg("invocationRepr", "args", keywordArgs.args, "table", true) checkTypeForNamedArg("invocationRepr", "options", keywordArgs.options, "table", true) local options = normalizeOptions(keywordArgs.options) local depth = options.depth options.depth = depth + 1 local items = {} if keywordArgs.args then for _, arg in ipairs(keywordArgs.args) do table.insert(items, repr(arg, options)) end end local prefix = "(" local suffix = ")" local separator = "," local renderedArgs if options.pretty then renderedArgs = prettyPrintItemsAtDepth( items, prefix, suffix, separator, getIndent(options), depth ) else renderedArgs = renderItems(items, prefix, suffix, separator) end return keywordArgs.funcName .. renderedArgs end return { _isLuaIdentifier = isLuaIdentifier, repr = repr, invocationRepr = invocationRepr, }
Summary:
Please note that all contributions to Stockhub may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Stockhub:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Templates used on this page:
Template:Sandbox other
(
edit
)
Module:Repr/doc
(
edit
)
Module:String
(
edit
)