七日内新公告:全站维护公告
  • 你好~!欢迎来到萌娘百科镜像站!如需查看或编辑,请联系本站管理员注册账号。
  • 本镜像站和其他萌娘百科的镜像站无关,请注意分别。

Module:Luaon

贴贴♀百科,万娘皆可贴的百科全书!转载请标注来源页面的网页链接,并声明引自贴贴百科。内容不可商用。
跳到导航 跳到搜索
Template-info.svg 模块文档  [创建] [刷新]




--[[
    本模块用于生成和解码mw.logObject式的标记语言Luaon,同时发布于模块Wiki(luamodule.miraheze.org)。
    所有状态储存在迭代器中。
    由User:杨哲思从本地编辑器上复制得来,因此下面的所有缩进都是空格,没有使用tab。
]]

local luaon = {}
--[[
local G_ = {[_G]='$_G'}
luaon.G = G_

local function mirror(t,prefix)
    for k,v in pairs(t) do
        if type(k)=='string'
        and (type(v)=='table'
            or type(v)=='function')
        then
            if type(v)=='table' then
                if not G_[v] then mirror(v,prefix..k..'.') end
                if not G_[v] or #G_[v]>#(prefix..k) then G_[v] = prefix..k end
                
            else
                if not G_[v] or #G_[v]>#(prefix..k) then G_[v] = prefix..k end
            end
        end
    end
end

mirror(_G,'$')
-- ]]
local ctrls = {
    ['\\n'] = '\n',
    ['\\\\'] = '\\',
    ['\\"'] = '"',
    ["\\'"] = "'"
}

local function encode(value,tables)
    local t = type(value)
    tables = tables or {len = 0}
    
    if t == 'string' then
        for k, v in pairs(ctrls) do
            value = value:gsub(v, k)
        end
        return string.format("'%s'",value)
    elseif t == 'number' then
        return tostring(value)
    elseif t == 'nil' then
        return 'nil'
    elseif t == 'boolean' then
        return tostring(value)
    end
    
    --if G_[value] then
        --return G_[value]
    --end
    
    if t == 'table' then
        if tables[value] then
            return '#'..tables[value]
        end
        tables[value] = tables.len + 1
        tables.len = tables.len + 1
        local output = '#'..tostring(tables[value])..'{'
        for k, v in pairs(value) do
            output = string.format('%s[%s]=%s,',output,encode(k,tables),encode(v,tables))
        end
        return output .. '}'
    else
        error('Unexpected type:'..t)
    end
end




local decode, tonum, tostr, tobool, totable, field, tovalue, space, toglobal

local function reader(str)
    local i = 0
    
    return function(l)
        if i + 1 > #str then return nil end
        if type(l)=='number' then
            i = i + l
            return str:sub(i-l+1, i)
        elseif l then
            return str:sub(i+1,i+1),i
        else
            i = i + 1
            return str:sub(i,i), str:sub(i+1,i+1), i
        end
    end
end

local function errorat(pos,char)
    error(string.format('Error at pos %s \'%s\'.',pos,char))
end


function decode(str)
    if type(str)~='string' then error('Luaon must be string') end
    local reading = reader(str)
    if str=="" then return end
    return tovalue(reading)
end

function tovalue(reading,tables)
    space(reading)
    tables = tables or {}
    local char, pos = reading(true)
    if char=='#' then
        return totable(reading,tables)
    elseif char:match '[%d%-]' then
        return tonum(reading)
    elseif char=='"' or char=="'" then
        return tostr(reading)
    elseif char=='t' or char=='f' or char=='n' then
        return tobool(reading)
    elseif char=='$' then
        return toglobal(reading)
    else
        error('unknown error at '..pos..char)
    end
end

function tonum(reading)
    local result = ''
    local c, p
    
    for char, nchar, pos in reading do
        result = result .. char
        if not nchar:match '[%d%.eE]' then
            c,p = char,pos
            break
        end
    end
    
    result = tonumber(result)
    
    if result then
        return result
    else
        error('Unknown error when scanning number at '..p.."'"..c.."'.")
    end
end

function tostr(reading)
    local start = reading()
    local str = ''
    
    for char, nchar, pos in reading do
        if char=='\\' then
            str = str..(ctrls[char..(reading())] or char..nchar)
        elseif char==start then
            return str
        else
            str = str .. char
        end
        if not nchar then break end
    end
    
    error('unfinished string "'..str..'"')
end

function tobool(reading)
    local bool ,_,pos= reading()
    bool = bool .. reading(2)
    if bool=="nil" then return nil end
    bool = bool .. (reading())
    if bool=="true" then return true end
    bool = bool .. (reading())
    if bool=="false" then return false end
    errorat(pos,bool)
end

function totable(reading,tables)
    reading()
    local id = tonum(reading)
    
    local result
    
    local index = 1
    if reading(true)=='{' then
        result = {}
        tables[id] = result
        for char, nchar, pos in reading do
            if char=='{' or char==',' then
                local key, value
                key, value, index = field(reading,tables,index)
                if key~=nil then result[key] = value end
            elseif char=='}' then
                return result
            else
                error('Error at '.. pos .."'"..char .."'.")
            end
        end
    else
        return tables[id] or error('Table not declared')
    end
end

local keyword = {
    ['do']=true,
    ['end']=true,
    ['function']=true,
    ['if']=true,
    ['then']=true,
    ['elseif']=true,
    ['else']=true,
    ['local']=true,
    ['while']=true,
    ['for']=true,
    ['in']=true,
    ['goto']=true,
    ['break']=true,
    ['repeat']=true,
    ['until']=true,
    ['not']=true,
    ['and']=true,
    ['or']=true,
    ['true']=true,
    ['false']=true,
    ['nil']=true,
    ['return']=true
}

function field(reading,tables,index)
    space(reading)
    local first = reading(true)
    local key, value
    
    space(reading)
    
    if first == '[' then
        
        local _,__,pos = reading()
        key = tovalue(reading,tables)
        if key==nil then error('Error at '..pos..':Table keys cannot be nil') end
        
        space(reading)
        local char, nchar, pos = reading()
        if char~=']' then error(string.format("error at %s '%s'.",pos,char)) end
        
        space(reading)
        local char, nchar, pos = reading()
        if char~='=' then error(string.format("error at %s '%s'.",pos,char)) end
        
        space(reading)
        value = tovalue(reading,tables)
        
        space(reading)
    elseif first:match '[%l_]' then
        key = ""
        local char,nchar,pos
        
       
        repeat
            char,nchar,pos = reading()
            key = key..char
        until nchar:match '%W'
        
        if keyword[key] then error('Unexpected keyword at '.. pos .. " '".. key .."'.") end
        
        space(reading)
        char, nchar, pos = reading()
        if char~='=' then error(string.format("error at %s '%s'.",pos,char)) end
        
        space(reading)
        value = tovalue(reading,tables)
        
        space(reading)
    elseif first=='}' or first==',' then
        return nil
    else
        key = index
        index = index + 1
        value = tovalue(reading,tables)
        space(reading)
    end
    return key, value, index
end

function toglobal(reading)
    
    reading()
    local char,nchar,pos
    
    local key = ''
        
       
    repeat
        char,nchar,pos = reading()
        key = key..char
    until nchar:match '%W'
    
    local global = _G
    
    return global[key] or error('No such global var')
end

function space(reading)
    while (reading(true)):match '%s' do
        reading()
    end
end

luaon.encode, luaon.decode = encode, decode

return luaon