FANDOM


local apiData = mw.loadData("Module:API/data")
local __ = require('Module:Underscore')
 
 
local types = {}
 
function types.isPrimitive(str)
    return (
        str == 'int' or
        str == 'bool' or
        str == 'void' or
        str == 'string' or
        str == 'float' or
        str == 'double' or
        str:lower() == 'function' or
        str:lower() == 'array' or
        str:lower() == 'dictionary'
    )
end
function types.isObject(str)
    return (str == 'Object' or str == 'Objects')
end
function types.isEnum(str)
    return not not apiData.Enums[str] --"not not" booleanifies
end
 
local simplifiedDisplays = {
    CoordinateFrame = "CFrame",
    RBXScriptSignal = "Signal"
}
 
local function basicLink(t)
    if types.isPrimitive(t) then
         t = t:lower()
    elseif t == "Property" then
        t = "string"
    elseif t == "Instance" then
        t = "Class/Instance"
    end
    local tdisp = t:gsub("^Class/","")
    if simplifiedDisplays[tdisp] then
        tdisp = simplifiedDisplays[tdisp]
    end
    return ('[[API:%s%s|<span %s>%s</span>]]'):format(
        types.isPrimitive(t) and 'Type/' or types.isEnum(t) and "Enum/" or '', -- first %s
        types.isObject(t) and 'Class/Instance' or t, -- second %s
        types.isPrimitive(t) and "style=\"color:green;\"" or "", -- in <span></span> (none originally #666362)
        tdisp
    )
end
 
types.link = function(ts, detuple)
    -- we've been passed a single type, not a list of types
    if #ts == 0 and ts.type then
        ts = {ts}
    end
 
    -- tuples can often omit the Tuple<>
    if detuple and #ts == 1 and ts[1].type == 'Tuple' and ts[1].args then
        ts = ts[1].args
    end
 
    return __.join(
        __.map(ts, function(t)
            local res
            if t.type:lower() == 'function' and t.args then
                if #t.args ~= 1 then error("function<> takes exactly one typearg") end
                if t.grouping ~= '<' then error("function typearg should be of the form 'ret(arg1, arg2)") end
 
                local returnType = t.args[1].type
                if returnType == "void" then 
                    returnType = "" -- Don't display <void> return type (it may confuse beginners)
                else
                    returnType = ("&lt;%s&gt;"):format(basicLink(returnType))
                end
 
                res =  ("%s%s(%s)"):format(
                    basicLink(t.type),  -- function
                    returnType,
                    types.link(t.args[1].args or {})
                )
            elseif t.grouping == '<' then
                res =  ("%s&lt;%s&gt;"):format(
                    basicLink(t.type),
                    types.link(t.args)
                )
            elseif t.grouping == '(' then
                res = ("%s&lt;%s&gt;(%s)"):format(
                    basicLink("function"),
                    basicLink(t.type),
                    types.link(t.args)
                )
            else
                res = basicLink(t.type)
            end
 
            if t.vararg then
                res = res .. '<span title="can be repeated">[[...]]</span>'
            elseif t.varName then
                res = res .. " " .. t.varName
            end
            return res
        end),
        ", "
    )
end
 
 
 
local tokens = {
    {'API_CLASS', 'Class/%w+'},
    {'TYPE', '[a-zA-Z_]+[a-zA-Z_0-9%.]+'},
    {'OPEN_GROUP', '[<(]'},
    {'CLOSE_GROUP', '[)>]'},
    {'SEPARATOR', ','},
    {'WHITESPACE', '%s+'},
    {'VARARG', '%.%.%.'}
}
 
local group_match = {
    ['('] = ')',
    ['<'] = '>'
}
 
local tokenize = function(s)
    local at = 1
 
    return function()
        for _, v in ipairs(tokens) do
            local name, pattern = unpack(v)
            local ms, me = s:find(pattern, at)
 
            if ms == at then
                at = me + 1
                return name, s:sub(ms, me)
            end
        end
        if at <= #s then
            mw.log(at, #s)
            error(("Could not parse token from %q"):format(s:sub(at, at+5)))
        end
    end
 
end
 
local parse = function(tokenstream)
    local was_type = false
 
    local result = {}
    local stack = {result}
 
    for t, s in tokenstream do
        local current = stack[#stack]
        if t == 'WHITESPACE' then
            -- pass
        elseif t == 'TYPE' or t == 'API_CLASS' then
            if was_type then
                --error("Type names must be separated by commas")
                current[#current].varName = s
            else
                table.insert(current, {type=s})
                was_type = true
            end
        elseif t == 'VARARG' then
            if not was_type then
                error("Vararg must follow type")
            else
                current[#current].vararg = true
            end
        elseif t == 'SEPARATOR' then
            if not was_type then
                error("Commas must follow a type name")
            else
                was_type = false
            end
        elseif t == 'OPEN_GROUP' then
            if not was_type then
                error("groups must begin after a type name")
            else
                current[#current].grouping = s
                current[#current].args = {}
                stack[#stack+1] = current[#current].args
                was_type = false
            end
        elseif t == 'CLOSE_GROUP' then
            local parent = stack[#stack-1]
            local open_s = parent[#parent].grouping
            if not was_type and #current ~= 0 then
                error("non-empty groups must end after a typename")
            elseif group_match[open_s] ~= s then
                error(("%s %s - Parens do not match: %s %s"):format(t, s, tostring(open_s), s))
            else
                stack[#stack] = nil
                was_type = true
            end
        else
            error(("Internal error - Unrecognized token name %q"):format(t))
        end
    end
 
    return result
end
 
 
function types.parse(s)
    assert(s and type(s) == 'string', ("Bad argument to tokenize: type %s"):format(type(s)))
    return parse(tokenize(s))
end
 
function types.render(frame)
    return types.link(types.parse(frame.args[1]))
end
 
-- Simple test case to check the code runs
local t = types.link(types.parse("Dictionary<string, int(int, Dictionary<int, string>), Variant>..."))
mw.log(t);
return types

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.