From 26624ddc9f0ffa61e269658de95c91e9a77c08a4 Mon Sep 17 00:00:00 2001
From: Philipp Gesang
More interesting it to implement a (sort of) dimen datatype, one @@ -132,27 +141,40 @@ local dimenpair = amount/tonumber * (unit^1/dimenfactors + Cc(1)) -- tonumber is lpeg.patterns.dimenpair = dimenpair +local splitter = amount/tonumber * C(unit^1) + +function number.splitdimen(str) + return lpegmatch(splitter,str) +end + --[[ldx--
We use a metatable to intercept errors. When no key is found in the table with factors, the metatable will be consulted for an alternative index function.
--ldx]]-- -local mt = { } setmetatable(dimenfactors,mt) - -mt.__index = function(t,s) +setmetatableindex(dimenfactors, function(t,s) -- error("wrong dimension: " .. (s or "?")) -- better a message return false -end +end) -function string:todimen() - if type(self) == "number" then - return self - else - local value, unit = lpegmatch(dimenpair,self) - return value/unit - end -end +--[[ldx-- +We redefine the following function later on, so we comment it +here (which saves us bytecodes.
+--ldx]]-- + +-- function string.todimen(str) +-- if type(str) == "number" then +-- return str +-- else +-- local value, unit = lpegmatch(dimenpair,str) +-- return value/unit +-- end +-- end +-- +-- local stringtodimen = string.todimen + +local stringtodimen -- assigned later (commenting saves bytecode) local amount = S("+-")^0 * R("09")^0 * S(".,")^0 * R("09")^0 local unit = P("pt") + P("cm") + P("mm") + P("sp") + P("bp") + P("in") + @@ -160,7 +182,7 @@ local unit = P("pt") + P("cm") + P("mm") + P("sp") + P("bp") + P("in") + local validdimen = amount * unit -lpeg.patterns.validdimen = pattern +lpeg.patterns.validdimen = validdimen --[[ldx--This converter accepts calls like:
@@ -174,12 +196,6 @@ string.todimen("10pt") string.todimen("10.0pt") -And of course the often more efficient:
- -With this in place, we can now implement a proper datatype for dimensions, one that permits us to do this:
@@ -197,28 +213,28 @@ local dimensions = { }The main (and globally) visible representation of a dimen is defined next: it is a one-element table. The unit that is returned from the match is normally a number (one of the previously defined factors) but we also accept functions. Later we will -see why.
+see why. This function is redefined later. --ldx]]-- -function dimen(a) - if a then - local ta= type(a) - if ta == "string" then - local value, unit = lpegmatch(pattern,a) - if type(unit) == "function" then - k = value/unit() - else - k = value/unit - end - a = k - elseif ta == "table" then - a = a[1] - end - return setmetatable({ a }, dimensions) - else - return setmetatable({ 0 }, dimensions) - end -end +-- function dimen(a) +-- if a then +-- local ta= type(a) +-- if ta == "string" then +-- local value, unit = lpegmatch(pattern,a) +-- if type(unit) == "function" then +-- k = value/unit() +-- else +-- k = value/unit +-- end +-- a = k +-- elseif ta == "table" then +-- a = a[1] +-- end +-- return setmetatable({ a }, dimensions) +-- else +-- return setmetatable({ 0 }, dimensions) +-- end +-- end --[[ldx--This function return a small hash with a metatable attached. It is @@ -228,35 +244,35 @@ shared some of the code but for reasons of speed we don't.
function dimensions.__add(a, b) local ta, tb = type(a), type(b) - if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end - if tb == "string" then b = b:todimen() elseif tb == "table" then b = b[1] end + if ta == "string" then a = stringtodimen(a) elseif ta == "table" then a = a[1] end + if tb == "string" then b = stringtodimen(b) elseif tb == "table" then b = b[1] end return setmetatable({ a + b }, dimensions) end function dimensions.__sub(a, b) local ta, tb = type(a), type(b) - if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end - if tb == "string" then b = b:todimen() elseif tb == "table" then b = b[1] end + if ta == "string" then a = stringtodimen(a) elseif ta == "table" then a = a[1] end + if tb == "string" then b = stringtodimen(b) elseif tb == "table" then b = b[1] end return setmetatable({ a - b }, dimensions) end function dimensions.__mul(a, b) local ta, tb = type(a), type(b) - if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end - if tb == "string" then b = b:todimen() elseif tb == "table" then b = b[1] end + if ta == "string" then a = stringtodimen(a) elseif ta == "table" then a = a[1] end + if tb == "string" then b = stringtodimen(b) elseif tb == "table" then b = b[1] end return setmetatable({ a * b }, dimensions) end function dimensions.__div(a, b) local ta, tb = type(a), type(b) - if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end - if tb == "string" then b = b:todimen() elseif tb == "table" then b = b[1] end + if ta == "string" then a = stringtodimen(a) elseif ta == "table" then a = a[1] end + if tb == "string" then b = stringtodimen(b) elseif tb == "table" then b = b[1] end return setmetatable({ a / b }, dimensions) end function dimensions.__unm(a) local ta = type(a) - if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end + if ta == "string" then a = stringtodimen(a) elseif ta == "table" then a = a[1] end return setmetatable({ - a }, dimensions) end @@ -321,23 +337,9 @@ is loaded, the relevant tables that hold the functions needed may not yet be available. --ldx]]-- -function dimensions.texify() -- todo: % - local fti, fc = fonts and fonts.ids and fonts.ids, font and font.current - if fti and fc then - dimenfactors["ex"] = function() return fti[fc()].ex_height end - dimenfactors["em"] = function() return fti[fc()].quad end - else - dimenfactors["ex"] = 1/65536* 4 -- 4pt - dimenfactors["em"] = 1/65536*10 -- 10pt - end -end - ---[[ldx-- -In order to set the defaults we call this function now. At some point -the macro package needs to make sure the function is called again.
---ldx]]-- - -dimensions.texify() + dimenfactors["ex"] = 4 * 1/65536 -- 4pt + dimenfactors["em"] = 10 * 1/65536 -- 10pt +-- dimenfactors["%"] = 4 * 1/65536 -- 400pt/100 --[[ldx--The previous code is rather efficient (also thanks to
Goodie:s
--ldx]]-- -function number.percent(n) -- will be cleaned up once luatex 0.30 is out - local hsize = tex.hsize - if type(hsize) == "string" then - hsize = hsize:todimen() +function number.percent(n,d) -- will be cleaned up once luatex 0.30 is out + d = d or tex.hsize + if type(d) == "string" then + d = stringtodimen(d) end - return (n/100) * hsize + return (n/100) * d end number["%"] = number.percent -- cgit v1.2.3