local c = {} -- module's table
local am = {} -- Elements with wiki links
am.H="[[Hydrogen|H]]"; am.He="[[Helium|He]]";
am.Li="[[Lithium|Li]]"; am.Be="[[Beryllium|Be]]"; am.B="[[Boron|B]]"; am.C="[[Carbon|C]]"; am.N="[[Nitrogen|N]]"; am.O="[[Oxygen|O]]"; am.F="[[Fluorine|F]]"; am.Ne="[[Neon|Ne]]" am.Phen="[[phenanthroline|Phen]]";
am.Ph="[[phenyl|Ph]]";
local T_ELEM = 0 -- token types
local T_NUM = 1
local T_O = 2 -- open '('
local T_C = 3 -- close ')'
local T_PM = 4 -- + or –
local T_MINUS = 5 -- -
local T_WATER = 6 -- .xH2O x number
local T_CRYSTAL = 9 -- .x
local T_REST = 7 -- small letters and random crap like ☃
local T_CHARGE = 8 -- charge (x+), (x-), (x–)
local T_SUF_CHARGE = 10 -- suffix and charge
local T_SUF_CHARGE2 = 12 -- suffix and (charge)
local T_SPECIAL = 14 -- starting with \ e.g. \d for double bond =
local T_SPECIAL2 = 16 -- starting with \ e.g. \d for double bond =
function su(a, b) -- like template su
return "<span style=\"display:inline-block; margin-bottom:-0.3em; vertical-align:-0.4em; line-height:1.2em; font-size:70%; text-align:left;\">" .. a .. "<br />" .. b .. "</span>";
end
function item(f) -- (iterator) returns one token (type, value) at a time from the formula 'f'
local i = 1
return function ()
local t, x = nil, nil
if i <= f:len() then
x = f:match('^%u%l*', i); t = T_ELEM; -- matching letters like Aaaaa
if not x then x = f:match('^%d+[%+|%-]', i); t = T_SUF_CHARGE; end -- matching x+, x-
if not x then x = f:match('^%d+%(%d*[+|%-]%)', i); t = T_SUF_CHARGE2; end -- matching x(x+/-), x(+/-)
if not x then x = f:match('^%(%d*[%+|%-]%)', i); t = T_CHARGE; end -- matching (x+) (xx+), (x-) (xx-)
if not x then x = f:match('^%d+', i); t = T_NUM; end -- matching number
if not x then x = f:match('^[(|{|%[]', i); t = T_O; end -- matching ({[
if not x then x = f:match('^[)|}|%]]', i); t = T_C; end -- matching )}]
if not x then x = f:match('^[+]', i); t = T_PM; end -- matching '+', xxxxx væk: '–' (long –)
if not x then x = f:match('^-', i); t = T_MINUS; end -- matching - (short)
if not x then x = f:match('^–', i); t = T_MINUS; end -- matching - (long) - stange output
if not x then x = f:match('^%.[0-9]*H2O', i); t = T_WATER; end -- Crystal water
if not x then x = f:match('^%.[0-9]+', i); t = T_CRYSTAL; end -- Crystal
if not x then x = f:match('^\.{%d+}', i); t = T_SPECIAL2; end -- \y[x]
if not x then x = f:match('^\.', i); t = T_SPECIAL; end -- \x
if not x then x = f:match('^.', i); t = T_REST; end --Resten en ad gangen
if x then i = i + x:len(); else i = i + 999; error("Invalid character in formula!!!!!!! : "..f) end
end
return t, x
end
end
function c.mm(frame) -- molar mass of the formula 'f'
local f = frame.args[1]
local config = frame.args
local link = frame.args['link']
local sum, cur = {0}, {0} -- stacks to handle '()' ; 'cur' awaits to be multiplied (or not)
local sumO = 0
local formel = ''
local t, x
local link = config.link or ""
if not (link == nil or link == '') then formel = formel .. "[[" .. link .. "|"; end -- wikilink start [[link|
for t, x in item(f) do
if t == T_ELEM then if not config.auto then formel = formel .. x elseif am[x] then formel = formel .. am[x]; am[x] = x;
else formel = formel .. x end
elseif t == T_REST then formel = formel .. x;
elseif t == T_NUM then formel = formel .. "<span style=\"display:inline-block; margin-bottom:-0.3em; vertical-align:-0.4em; line-height:1.2em; font-size:70%; text-align:right;\">" .. x .."</span>"; -- su|w=70%|a=r|p={{{1}}}|b={{{2}}}}}
elseif t == T_O then formel = formel .. x; sumO = sumO + 1; -- ( {
elseif t == T_C then formel = formel .. x; sumO = sumO -1; -- ) }
-- elseif t == T_PM then formel = formel .. "aaaa" .. "<sup>" .. string.gsub(x, "-", "–") .. "</sup>";
elseif t == T_PM then formel = formel .. "<sup>" .. x .. "</sup>";
elseif t == T_MINUS then formel = formel .. "<sup>–</sup>";
elseif t == T_SUF_CHARGE then
formel = formel .. su(string.gsub(string.match(x, "[%+|%-|–]"), "-", "–"), string.match(x, "%d+"));
---x
elseif t == T_SUF_CHARGE2 then
formel = formel .. su(string.sub(string.gsub(string.match(x, "%(%d*[+|%-]"), "-", "–"), 2, -1), string.match(x, "%d+"))
elseif t == T_CHARGE then formel = formel .. "<sup>"; if string.match(x, "%d+") then formel = formel .. string.match(x, "%d+"); end formel = formel .. string.gsub(string.match(x, "[%-|%–|%+]"), "-", "–") .. "</sup>"; -- can not concatenat a nil value from string.match(x, "%d+");
elseif t == T_WATER then formel = formel .. ' <span style="font-weight:bold;">·</span> ' .. "[[Water of crystallization|H<sub>2</sub>O]]";
elseif t == T_CRYSTAL then formel = formel .. ' <span style="font-weight:bold;">·</span> ' .. string.gsub( x, ".", ' ', 1 );
elseif t == T_SPECIAL then
if x == "\s" then formel = formel .. "–" -- single bond
elseif x == "\d" then formel = formel .. "=" -- double bond
elseif x == "\t" then formel = formel .. "a≡" end -- double bond
elseif t == T_SPECIAL2 then -- \y{x}
if string.sub(x, 1, 1) == "h" then formel = formel .. "η<sup>" .. string.match(x, '%d+') .. "</sup>"
else formel = formel .. x end
else error('unreachable - ???') end -- in fact, unreachable
end
if sumO > 0 then formel = formel .. "'<span style=\"display:none;font-size:100%\" class=\"error citation-comment\"> Too many (</span>'\";"
elseif sumO < 0 then formel = formel .. "'<span style=\"display:none;font-size:100%\" class=\"error citation-comment\"> Too many )</span>'\";"
end
if not (link == nil or link == '') then formel = formel .. "]]"; end -- wikilink closing ]]
return formel
end
return c -- exports c.mm()