Module:Calc

local Utils = require("Module:Utils") local format = require("Module:StringOperations").format local Formatting = require("Module:Formatting") local Ship = require("Module:Ship") local ShipIterator = require("Module:ShipIterator") local ShipCapabilities = require("Module:ShipCapabilities")

local debug = {}

function debugLog(s) table.insert(debug, s) end

function debugSpan return #debug > 0 and ( .. table.concat(debug, "\n") ..  ) or "" end

local args = nil local ship = nil local target = nil local shipCapabilities = nil local frame = nil

local enumerating_functions = {

args = function return mw.text.split(args.args, "%s*,%s*") end,

base_names = function return ShipIterator.baseForms end,

all_names = function return ShipIterator.allForms end, enemy = function return ShipIterator.enemyForms end,

}

-- TODO: have a syntax for calling Module:Formatting functions? local formatting_functions = {

night_battle_power = function(ship) return (ship:firepower_max or 0) + (ship:torpedo_max or 0) end, code = function(ship) return Formatting:format_ship_code(ship:type) end,

-- overrides ShipData:type type = function(ship) return Formatting:format_ship_type(ship:type) end,

-- overrides ShipData:link link = function(ship) return Formatting:format_link(ship:link) end,

-- overrides ShipData:implementation_date implementation_date = function(ship) local date = ship:implementation_date return not date and "??" or format{ "${year}/${month}/${day}", year = date[1], month = date[2] < 10 and "0" .. date[2] or date[2], day = date[3] < 10 and "0" .. date[3] or date[3], }   end,

test = function return (ship:level or 0) + (ship._accuracy or 0) - (target:evasion or 0) end,

}

function format_lua(lua) if type(lua) == "table" then return tostring(table.concat(lua, args.concat_value or ", ")) else return tostring(lua) end end

function format_value(key) local formatting_function = formatting_functions[key] if formatting_function then return formatting_function(ship, target) else if shipCapabilities[key] then local a, b = shipCapabilities[key](shipCapabilities) return format_lua(b or a)       else local lua = ship[key] if type(lua) == "function" then return format_lua(lua(ship)) else return format_lua(lua) end end end end

local sequence = nil local sequence_position = nil

function interpret_arg(arg) local prefix = string.sub(arg, 1, 1) local prefix2 = string.sub(arg, 1, 2) if prefix == "@" then local enumerator = string.sub(arg, 2) local enumerating_function = enumerating_functions[enumerator] if enumerating_function and not sequence then sequence = enumerating_function sequence_position = 1 end elseif arg == "!@" then local ship_key = sequence[sequence_position] sequence_position = sequence_position + 1 ship = Ship(ship_key) shipCapabilities = ShipCapabilities{ ship = ship } elseif prefix2 == "!!" then local key = string.sub(arg, 3) target = Ship(key) elseif prefix == "!" then local ship_key = string.sub(arg, 2) if string.sub(ship_key, 1, 1) == "_" and ship then local kv = mw.text.split(ship_key, "%s*=%s*") local k = kv[1] local v = kv[2] if k and v then if k == "_equipment" then local equipment = {} for eq in string.gmatch(v, '([^,]+)') do                       table.insert(equipment, { equipment = eq }) end ship._equipment = equipment else ship[k] = tonumber(v) end end else local parts = string.gmatch(ship_key, '([^:]+)') local i = 1 for part in parts do               if i == 1 then ship_key = part ship = Ship(ship_key) shipCapabilities = ShipCapabilities{ ship = ship } else local kv = mw.text.split(part, "%s*=%s*") local k = kv[1] local v = kv[2] if k and v then if k == "_equipment" then local equipment = {} for eq in string.gmatch(part, '([^,]+)') do                               table.insert(equipment, { equipment = eq }) end ship._equipment = equipment else ship[k] = tonumber(v) end end end i = i + 1 end end elseif prefix == "#" and args.format == "table" then return "|-\n" elseif prefix == "?" then prefix = string.sub(arg, 2, 2) if prefix == "?" then local key = string.sub(arg, 3) return frame:preprocess(format{               '',                template = key,                ship = ship:name('/')            }) else local key = string.sub(arg, 2) local value = format_value(key) if args.format == "table" then return "|" .. value .. "\n" else return value end end else return arg end end

local special_functions = { apply = function(args_) local frame_ = frame:getParent local template = args_[2] local values = {} for i = 3, #args_ do           table.insert(values, format{                '',                template = template,                arg = args_[i]            }) end return frame_:preprocess(table.concat(values, args.concat or "")) end }

function interpret_args(args_) args = args_ local special_function = special_functions[args[1]] if special_function then return special_function(args) else local values = {} repeat for _, arg in ipairs(args_) do               debugLog("arg = " .. (arg or "")) local value = interpret_arg(arg) if value then debugLog("value = " .. (value or "")) table.insert(values, value) end end until not sequence or sequence_position > #sequence return table.concat(values, args.concat or "") .. debugSpan end end

local Calc = {}

function Calc.format(frame_, args_) frame = frame_ return interpret_args(args_ or Utils.getTemplateArgs(frame_).explicit) end

function Calc.test mw.log(       Calc.format(nil, { "!Nagato/Kai Ni:_hp = 1", --"!_level = 99", --"!_accuracy = 10", --"!!Destroyer Ro-Class", "?hp" })   ) end

return Calc