Module:Calculate

local p = {} local expr = mw.ext.ParserFunctions.expr local getArgs = require( 'Module:Arguments' ).getArgs local split = require( 'Module:Split' ) local yesno = require( 'Module:Yesno' )

local i18n = { value_separator = '/', error_no_expression = 'Enter an expression', }

function p.main( frame ) local args = getArgs( frame, {   wrappers = {      'Template:Calculate'    }  } ) return p._main( args ) end

function p._main( args ) local calculate = function( calc ) -- Replaces percentage signs with /100 since #expr can't handle them. calc = string.gsub( calc, '%%', '/100' ) local success, result = pcall( expr, calc ) if success then return result else -- Remove the leading "Expression error: " and the trailing ".". local error_message = result:sub( 19, -2 ) -- Add the faulty expression to make debugging easier. local error_message = string.format( '%s in expression "%s"', error_message, calc )

error( error_message ) end end

assert( args and args[1], i18n.error_no_expression ) if args['v1'] then -- Create a table that holds a table for each v argument. local v_values = {} local n = 1 while args['v'..n] do     -- Escape percentage signs to prevent them from escaping the / during the split. v = string.gsub( args['v'..n], '%%', '%%%%' ) -- Split the v into the individual values and add them to the v_values table. table.insert( v_values, split( v, i18n.value_separator ) ) n = n + 1 end

local output = {} -- Run once for each value in the v1 argument. for level=1,#v_values[1] do     local calc = args[1] -- Do a replacement for each v arg. for i,v in ipairs( v_values ) do       calc = calc:gsub( 'v'..i, v[level] ) end

-- Solve the calculation we just constructed and insert it into the output. -- args[2] is used to trigger special percentage handling. if yesno( args.percent ) or args[2] then table.insert( output, calculate( '( '..calc..' )*100' ) .. '%' ) else table.insert( output, calculate( calc ) ) end end

-- Return the values in the output table separated by a /. return table.concat( output, i18n.value_separator ) else -- Just do a normal #expr if no v values are given. -- Still has percentage handling which normal #expr doesn't.   -- TODO: Remove the args[2] once all pages are transitioned. if yesno( args.percent ) or args[2] then return calculate( '( '..args[1]..' )*100' ) .. '%'   else return calculate( args[1] ) end end end

return p