模块:Var-array/main

来自理想城计划

可在模块:Var-array/main/doc创建此模块的帮助文档

local module = {}

local getArgs = require("Module:Arguments").getArgs
local varArray = require("Module:var-array")
local var = require("Module:var")

local frame = mw.getCurrentFrame()

local _count = {
  get = function(array)
    return var.get(array .. ".count")
  end
}

_count.plus = function(array)
  return tonumber(var.set(array .. ".count", _count.get(array) + 1))
end

_count.minus = function(array)
  return tonumber(var.set(array .. ".count", _count.get(array) - 1))
end

local prefix = "@array-innerArrayIdentifier:"
function _ifArrayIndex(val)
  return (tostring(val or ''):find("^@array%-innerArrayIdentifier:.+"))
end

function _getArrayIndex(args, askValueIndex)
  local arrayIndex = prefix .. args[2]
  if arrayIndex ~= var.getPlain(arrayIndex) then
    error("变量组名无效", 0)
  end

  local argsCount = 0
  if askValueIndex then
    for i, v in ipairs(args) do
      argsCount = i
    end
  end
  for i, v in ipairs(args) do
    if i > 2 then
      if askValueIndex and i == argsCount then
        arrayIndex = arrayIndex .. v
      else
        if (v == "count") then
          v = ".count"
        end
        arrayIndex = var.getPlain(arrayIndex .. v)
      end
    end
  end

  return arrayIndex
end

function _new(args, isOmit)
  local id = args["id"] or args["name"]
  if id == nil then
    error("构造变量组时“name”或“id”不能为空", 0)
  end
  local name = prefix .. id
  var.set(name, name)

  -- 用ipairs遍历args在遇到空匿名参数时会中断
  local count = 0
  for i, v in pairs(args) do
    if tostring(i):find("^%d+$") then
      i = tonumber(i)
      if isOmit then
        var.set(name .. i, v)
        if i > count then
          count = i
        end
      elseif i > 1 then
        i = i - 1
        var.set(name .. i, v)
        if i > count then
          count = i
        end
      end
    end
  end
  var.set(name .. ".count", count)

  var.set("array.savedNameUseForArrayId", id)
  return id
end

function _id()
  local savedName = var.get("array.savedNameUseForArrayId") or math.random()
  local idCount = (var.get("array.idCount") or 0) + 1
  var.set("array.idCount", idCount)
  return prefix .. savedName .. "___" .. idCount .. "___"
end

function _in(args)
  local name = _id()
  local count = 0
  var.set(name, name)
  for i, v in pairs(args) do
    if tostring(i):find("^%d+$") then
      i = tonumber(i)
      if i > 1 then
        i = i - 1
        var.set(name .. i, v)
        if i > count then
          count = i
        end
      end
    end
  end
  var.set(name .. ".count", count)

  return name
end

function _get(args)
  local result = _getArrayIndex(args)
  if _ifArrayIndex(result) then
    error("不能获取变量组的索引值", 0)
  end
  return result
end

function _set(args)
  local index = _getArrayIndex(args, true)
  if _ifArrayIndex(var.get(index)) then
    error("不能对变量组索引进行赋值", 0)
  end

  return var.set(index, args["val"])
end

function _push(val, array, count)
  var.set(array .. (count + 1), val)
  return _count.plus(array)
end

function _pop(array, count)
  if count == 0 then
    return
  end
  _count.minus(array)
  return var.remove(array .. count)
end

function _unshift(val, array, count)
  for i = count, 1, -1 do
    local val = var.getPlain(array .. i)
    var.set(array .. (i + 1), val)
  end
  var.set(array .. "1", val)
  return _count.plus(array)
end

function _shift(array, count)
  if count == 0 then
    return
  end
  local deletedVal = var.getPlain(array .. 1)
  for i = 2, count do
    local val = var.getPlain(array .. i)
    var.set(array .. (i - 1), val)
  end
  var.set(array..count, '')
  
  _count.minus(array)
  return deletedVal
end

function _splice(array, count, startIndex, howmany, args)
  local vals = {}
  for i, v in pairs(args) do
    if tostring(i):find("^%d+$") then
      i = tonumber(i)
      if i > 1 then
        vals[#vals + 1] = v
      end
    end
  end
  
  if howmany == #vals then
  	for i=1, howmany do
  	  var.set(array..(startIndex + i - 1), vals[i])	
  	end
    return count
  else
  	local fragment = {}
  	for i=startIndex + howmany, count do
  	  fragment[#fragment + 1] = var.remove(array..i)
  	end
  	
  	for i=1, #vals do
  	  var.set(array..(startIndex + i - 1), vals[i])	
  	end
  	
  	-- 删除操作起始点和尾部保存起始点之间的成员
  	local d_start = startIndex + #vals
  	local d_end = count - #fragment
  	local d_count = d_end - d_start + 2
  	if d_count > #vals then
  	  for i=d_start, d_end do
  	  	var.set(i, '')
  	  end
  	end
  	
  	count = startIndex - 1 + #vals
  	for i=1, #fragment do
  	  var.set(array..(count + i), fragment[i])	
  	end
  	
  	return var.set(array..'.count', count + #fragment)
  end
end

function module.main(frame)
  local args = getArgs(frame)

  function ifReturn(val)
    if args["r"] == "true" then
      return val
    end
    return ""
  end

  function getArray()
    local array = _getArrayIndex(args)
    if array == "" then
      error("变量组成员下标(序号)定位有误", 0)
    end
    local count = _count.get(array)
    return array, count
  end

  local switch = {
    new = function()
      return ifReturn(_new(args))
    end,

    ["in"] = function()
      return _in(args)
    end,

    get = function()
      return _get(args)
    end,

    set = function()
      return ifReturn(_set(args))
    end,

    push = function()
      local array, count = getArray()
      return ifReturn(_push(args["val"], array, count))
    end,

    pop = function()
      local array, count = getArray()
      return ifReturn(_pop(array, count))
    end,

    unshift = function()
      local array, count = getArray()
      return ifReturn(_unshift(args["val"], array, count))
    end,

    shift = function()
      local array, count = getArray()
      return ifReturn(_shift(array, count))
    end,
    
    getIndex = function()
      return _getArrayIndex(args)
    end,
    
    ifIndex = function()
      if _ifArrayIndex(args[2]) then
        return 1
      end
    end,
    
    splice = function()
      local array = args['index']
      local count = var.get(array..'.count')
      local start = tonumber(args['start'] or 1)
      local howmany = tonumber(args['howmany'] or 1)
      if start > count then error('start参数(操作起点)不能大于变量组的长度', 0) end
      if _ifArrayIndex(array) 
        then return ifReturn(_splice(array, count, start, howmany, args))
        else error('变量组索引无效', 0)
      end
    end,

    print = function()
      local content = mw.dumpObject(varArray.get((getArray()):gsub("^@array%-innerArrayIdentifier:", "")))
      return frame:extensionTag("pre", content)
    end
  }

  local hasTargetMethod = false
  for k, v in pairs(switch) do
    if k == args[1] then
      hasTargetMethod = true
      break
    end
  end

  if hasTargetMethod then
    return switch[args[1]]()
  else
    return ifReturn(_new(args, true))
  end
end

return module