Module:CompilerExplorer

From emmtrix Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:CompilerExplorer/doc

local p = {}

-- URL encoding for strings
function urlencode(url)
    if not url then return nil end
    return (url:gsub("%+", "%%2B")
               :gsub(" ", "+")
               :gsub("\n", "%%0A")
               :gsub("\"", "%%22"))
end

-- Function to escape single quotes in strings
local function escapeString(str)
    return str:gsub("!", "!!"):gsub("'", "!'")
end

-- Serialize a Lua table into the custom format
local function serializeTable(t, root)
    if type(t) == "string" then
        return "'" .. escapeString(t) .. "'"
    elseif type(t) == "table" then
        local isArray = #t > 0
        local items = {}
        if isArray then
            -- Handle as an array
            for _, v in ipairs(t) do
                table.insert(items, serializeTable(v, false))
            end
            if root then
                return table.concat(items, ",")
            else
                return "!(" .. table.concat(items, ",") .. ")"
            end
        else
            -- Handle as an object (key/value pairs)
            for k, v in pairs(t) do
                table.insert(items, k .. ":" .. serializeTable(v, false))
            end
            if root then
                return table.concat(items, ",")
            else
                return "(" .. table.concat(items, ",") .. ")"
            end
        end
    else
        -- Directly return other types (numbers, booleans)
        return tostring(t)
    end
end

-- Main function to generate the Compiler Explorer link
function p.generateLink(frame)
    local source = frame.args.source or ""
    local options = frame.args.options or ""
    local compiler = frame.args.compiler or "clang1600"
    local lang = frame.args.lang or "c++"
    local langname

	if lang == "c++" then
		langname = "C++"
	elseif lang == "c" then
		langname = "C"
		lang = "___c"
		compiler = "c" .. compiler
	else
		return "Invalid lang"
	end

	local compilername
    local major, minor, patch = compiler:match("clang(%d+)(%d)(%d)")
    if (major) then
    	compilername = string.format("x86-64 clang %s.%s.%s", major, minor, patch)
    end

	local template = "g:!((g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:<lang>,selection:(endColumn:2,endLineNumber:4,positionColumn:2,positionLineNumber:4,selectionStartColumn:2,selectionStartLineNumber:4,startColumn:2,startLineNumber:4),source:<source>),l:'5',n:'0',o:'C++ source #1',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:<compiler>,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c++,libs:!(),options:'<options>',overrides:!(),selection:(endColumn:12,endLineNumber:7,positionColumn:12,positionLineNumber:7,selectionStartColumn:12,selectionStartLineNumber:7,startColumn:12,startLineNumber:7),source:1),l:'5',n:'0',o:' <compilername> (Editor #1)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',m:50,n:'0',o:'',t:'0'),(g:!((h:output,i:(compilerName:'<compilername>',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output of <compilername> (Compiler #1)',t:'0')),header:(),l:'4',m:50,n:'0',o:'',s:0,t:'0')),l:'3',n:'0',o:'',t:'0')),version:4"
	local template2 = "g:!((g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:<lang>,source:<source>),l:'5',n:'0',o:'<langname>+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:<compiler>,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:<lang>,libs:!(),options:'<options>',overrides:!(),source:1),l:'5',n:'0',o:'<compilername>+(Editor+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',m:50,n:'0',o:'',t:'0'),(g:!((h:output,i:(compilerName:'<compilername>',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output+of+<compilername>+(Compiler+%231)',t:'0')),header:(),l:'4',m:50,n:'0',o:'',s:0,t:'0')),l:'3',n:'0',o:'',t:'0')),version:4"

	local param = template2
	    :gsub("<source>", serializeTable(source))
	    :gsub("<lang>", lang)
	    :gsub("<langname>", langname)
	    :gsub("<compiler>", compiler)
	    :gsub("<compilername>", compilername)
	    :gsub("<options>", options)

    local fullUrl = "https://godbolt.org/#" .. urlencode(param)

	return fullUrl
	-- return frame:preprocess(string.format('{{#widget:LinkWithTitle|href=%s|text=Open in Compiler Explorer|title=Compiler Explorer}}', fullUrl))
end

return p