summaryrefslogtreecommitdiff
path: root/tex/context/base/mkxl/phys-dim.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkxl/phys-dim.lmt')
-rw-r--r--tex/context/base/mkxl/phys-dim.lmt1116
1 files changed, 1116 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/phys-dim.lmt b/tex/context/base/mkxl/phys-dim.lmt
new file mode 100644
index 000000000..8575962e9
--- /dev/null
+++ b/tex/context/base/mkxl/phys-dim.lmt
@@ -0,0 +1,1116 @@
+if not modules then modules = { } end modules ['phys-dim'] = {
+ version = 1.001,
+ comment = "companion to phys-dim.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This is pretty old code that I found back, but let's give it a try
+-- in practice. It started out as m-units.lua but as we want to keep that
+-- module around we moved the code to the dimensions module.
+--
+-- todo: maybe also an sciunit command that converts to si units (1 inch -> 0.0254 m)
+-- etc .. typical something to do when listening to a news whow or b-movie
+--
+-- todo: collect used units for logging (and list of units, but then we need
+-- associations too).
+
+-- The lists have been checked and completed by Robin Kirkham.
+
+-- dubious/wrong
+
+-- Atom = [[u]], -- should be amu (atomic mass unit)
+-- Bell = [[B]], -- should be bel
+-- Sterant = [[sr]], -- should be steradian
+-- Equivalent = [[eql]], -- qualifier?
+-- At = [[at]], -- qualifier?
+-- Force = [[f]], -- qualifier?
+-- eVolt = [[eV]],
+-- -- AC or DC voltages should be qualified in the text
+-- VoltAC = [[V\unitsbackspace\unitslower{ac}]],
+-- VoltDC = [[V\unitsbackspace\unitslower{dc}]],
+-- AC = [[V\unitsbackspace\unitslower{ac}]],
+-- DC = [[V\unitsbackspace\unitslower{dc}]],
+-- -- probably not harmful but there are better alternatives
+-- -- e.g., revolution per second (rev/s)
+-- RPS = [[RPS]],
+-- RPM = [[RPM]],
+-- RevPerSec = [[RPS]],
+-- RevPerMin = [[RPM]],
+
+local rawset, next = rawset, next
+local V, P, S, R, C, Cc, Cs, matchlpeg = lpeg.V, lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.match
+local format, lower, gsub = string.format, string.lower, string.gsub
+local appendlpeg = lpeg.append
+local utfchartabletopattern = lpeg.utfchartabletopattern
+local mergetable, mergedtable, keys, loweredkeys, sortedhash = table.merge, table.merged, table.keys, table.loweredkeys, table.sortedhash
+local setmetatablenewindex = table.setmetatablenewindex
+local utfchar = utf.char
+
+physics = physics or { }
+physics.units = physics.units or { }
+
+local allocate = utilities.storage.allocate
+
+local context = context
+local commands = commands
+local implement = interfaces.implement
+
+local trace_units = false
+local report_units = logs.reporter("units")
+
+trackers.register("physics.units", function(v) trace_units = v end)
+
+-- digits parser (todo : use patterns)
+
+local math_one = Cs((P("$") /"") * (1-P("$"))^1 * (P("$")/"")) / context.m
+local math_two = Cs((P("\\m {")/"") * (1-P("}"))^1 * (P("}")/"")) / context.m -- watch the space after \m
+
+local digit = R("09")
+local plus = P("+")
+local minus = P("-")
+local plusminus = P("±")
+local sign = plus + minus
+local power = S("^e")
+local digitspace = S("~@_")
+local comma = P(",")
+local period = P(".")
+local semicolon = P(";")
+local colon = P(":")
+local signspace = P("/")
+local positive = P("++") -- was p
+local negative = P("--") -- was n
+local highspace = P("//") -- was s
+local padding = P("=")
+local space = P(" ")
+local lparent = P("(")
+local rparent = P(")")
+
+local lbrace = P("{")
+local rbrace = P("}")
+
+local digits = digit^1
+
+local powerdigits = plus * C(digits) / context.digitspowerplus
+ + minus * C(digits) / context.digitspowerminus
+ + C(digits) / context.digitspower
+
+local ddigitspace = digitspace / "" / context.digitsspace
+local ddigit = digits / context.digitsdigit
+local dsemicomma = semicolon / "" / context.digitsseparatorspace
+local dsemiperiod = colon / "" / context.digitsseparatorspace
+local dfinalcomma = comma / "" / context.digitsfinalcomma
+local dfinalperiod = period / "" / context.digitsfinalperiod
+local dintercomma = comma / "" / context.digitsintermediatecomma
+local dinterperiod = period / "" / context.digitsintermediateperiod
+local dskipcomma = comma / "" / context.digitsseparatorspace
+local dskipperiod = period / "" / context.digitsseparatorspace
+local dsignspace = signspace / "" / context.digitssignspace
+local dpositive = positive / "" / context.digitspositive
+local dnegative = negative / "" / context.digitsnegative
+local dhighspace = highspace / "" / context.digitshighspace
+local dsomesign = plus / "" / context.digitsplus
+ + minus / "" / context.digitsminus
+ + plusminus / "" / context.digitsplusminus
+local dpower = power / "" * ( powerdigits + lbrace * powerdigits * rbrace )
+
+local dpadding = padding / "" / context.digitszeropadding -- todo
+
+local dleader = (dpositive + dnegative + dhighspace + dsomesign + dsignspace)^0
+local dtrailer = dpower^0
+local dfinal = P(-1) + #P(1 - comma - period - semicolon - colon)
+local dnumber = (ddigitspace + ddigit)^1
+
+-- ___,000,000 ___,___,000 ___,___,__0 000,000,000 000.00 000,000,000.00 000,000,000.==
+
+-- : ; for the moment not used, maybe for invisible fraction . , when no leading number
+
+-- local c_p = (ddigitspace^1 * dskipcomma)^0 -- ___,
+-- * (ddigitspace^0 * ddigit * dintercomma)^0 -- _00, 000,
+-- * ddigitspace^0 * ddigit^0 -- _00 000
+-- * (
+-- dfinalperiod * ddigit -- .00
+-- + dskipperiod * dpadding^1 -- .==
+-- + dsemiperiod * ddigit -- :00
+-- + dsemiperiod * dpadding^1 -- :==
+-- )^0
+-- + ddigit -- 00
+--
+-- local p_c = (ddigitspace^1 * dskipperiod)^0 -- ___.
+-- * (ddigitspace^0 * ddigit * dinterperiod)^0 -- _00. 000.
+-- * ddigitspace^0 * ddigit^0 -- _00 000
+-- * (
+-- dfinalcomma * ddigit -- ,00
+-- + dskipcomma * dpadding^1 -- ,==
+-- + dsemicomma * ddigit -- :00
+-- + dsemicomma * dpadding^1 -- :==
+-- )^0
+-- + ddigit -- 00
+--
+-- fix by WS/SB (needs further testing)
+
+local c_p = (ddigitspace^1 * dskipcomma)^0 -- ___,
+ * (ddigitspace^0 * ddigit * dintercomma)^0 -- _00, 000,
+ * ddigitspace^0 * ddigit^0 -- _00 000
+ * (
+ dfinalperiod * ddigit^1 * dpadding^1 -- .0=
+ + dfinalperiod * ddigit * (dintercomma * ddigit)^0 -- .00
+ + dskipperiod * dpadding^1 -- .==
+ + dsemiperiod * ddigit * (dintercomma * ddigit)^0 -- :00
+ + dsemiperiod * dpadding^1 -- :==
+ )^0
+ + ddigit -- 00
+
+local p_c = (ddigitspace^1 * dskipperiod)^0 -- ___.
+ * (ddigitspace^0 * ddigit * dinterperiod)^0 -- _00. 000.
+ * ddigitspace^0 * ddigit^0 -- _00 000
+ * (
+ dfinalcomma * ddigit^1 * dpadding^1 -- ,0=
+ + dfinalcomma * ddigit * (dinterperiod * ddigit)^0 -- 00
+ + dskipcomma * dpadding^1 -- ,==
+ + dsemicomma * ddigit * (dinterperiod * ddigit)^0 -- :00
+ + dsemicomma * dpadding^1 -- :==
+ )^0
+ + ddigit -- 00
+
+local p_c_dparser = math_one + math_two + dleader * p_c * dtrailer * dfinal
+local c_p_dparser = math_one + math_two + dleader * c_p * dtrailer * dfinal
+
+local function makedigits(str,reverse)
+ if reverse then
+ matchlpeg(p_c_dparser,str)
+ else
+ matchlpeg(c_p_dparser,str)
+ end
+end
+
+-- tables:
+
+local user_long_prefixes = { }
+local user_long_units = { }
+local user_long_operators = { }
+local user_long_suffixes = { }
+local user_symbol_units = { }
+local user_packaged_units = { }
+
+local user_short_prefixes = { }
+local user_short_units = { }
+local user_short_operators = { }
+local user_short_suffixes = { }
+
+local long_prefixes = {
+
+ -- Le Système international d'unités (SI) 8e édition (Table 5)
+
+ Yocto = "yocto", -- 10^{-24}
+ Zepto = "zepto", -- 10^{-21}
+ Atto = "atto", -- 10^{-18}
+ Femto = "femto", -- 10^{-15}
+ Pico = "pico", -- 10^{-12}
+ Nano = "nano", -- 10^{-9}
+ Micro = "micro", -- 10^{-6}
+ Milli = "milli", -- 10^{-3}
+ Centi = "centi", -- 10^{-2}
+ Deci = "deci", -- 10^{-1}
+
+ Deca = "deca", -- 10^{1}
+ Hecto = "hecto", -- 10^{2}
+ Kilo = "kilo", -- 10^{3}
+ Mega = "mega", -- 10^{6}
+ Giga = "giga", -- 10^{9}
+ Tera = "tera", -- 10^{12}
+ Peta = "peta", -- 10^{15}
+ Exa = "exa", -- 10^{18}
+ Zetta = "zetta", -- 10^{21}
+ Yotta = "yotta", -- 10^{24}
+
+ -- IEC 60027-2: 2005, third edition, Part 2
+
+ Kibi = "kibi", -- 2^{10} (not ki)
+ Mebi = "mebi", -- 2^{20}
+ Gibi = "gibi", -- 2^{30}
+ Tebi = "tebi", -- 2^{40}
+ Pebi = "pebi", -- 2^{50}
+ Exbi = "exbi", -- 2^{60}
+
+ -- not standard
+
+ Zebi = "zebi", -- binary
+ Yobi = "yobi", -- binary
+
+ Micro = "micro",
+ Root = "root",
+}
+
+local long_units = {
+
+ -- Le Système international d'unités (SI) 8e édition (except synonyms)
+ -- SI base units (Table 1)
+
+ Meter = "meter",
+ Gram = "gram",
+ Second = "second",
+ Ampere = "ampere",
+ Kelvin = "kelvin",
+ Mole = "mole",
+ Candela = "candela",
+
+ -- synonyms
+
+ Mol = "mole",
+ Metre = "meter",
+
+ -- SI derived units with special names (Table 3)
+
+ Radian = "radian",
+ Steradian = "steradian",
+ Hertz = "hertz",
+ Newton = "newton",
+ Pascal = "pascal",
+ Joule = "joule",
+ Watt = "watt",
+ Coulomb = "coulomb",
+ Volt = "volt",
+ Farad = "farad",
+ Ohm = "ohm",
+ Siemens = "siemens",
+ Weber = "weber",
+ Tesla = "tesla",
+ Henry = "henry",
+ Celsius = "celsius",
+ Lumen = "lumen",
+ Lux = "lux",
+ Becquerel = "becquerel",
+ Gray = "gray",
+ Sievert = "sievert",
+ Katal = "katal",
+
+ -- non SI units accepted for use with SI (Table 6)
+
+ Minute = "minute",
+ Hour = "hour",
+ Day = "day",
+
+ -- (degree, minute, second of arc are treated specially later)
+
+ Gon = "gon",
+ Grad = "grad",
+ Hectare = "hectare",
+ Liter = "liter",
+
+ Tonne = "tonne",
+
+ -- synonyms
+
+ MetricTon = "tonne",
+ Litre = "liter",
+
+ ["Metric Ton"] = "tonne",
+
+ -- non-SI units whose values must be obtained experimentally (Table 7)
+
+ AtomicMassUnit = "atomicmassunit",
+ AstronomicalUnit = "astronomicalunit",
+ ElectronVolt = "electronvolt",
+ Dalton = "dalton",
+
+ ["Atomic Mass Unit"] = "atomicmassunit",
+ ["Astronomical Unit"] = "astronomicalunit",
+ ["Electron Volt"] = "electronvolt",
+
+ -- special cases (catch doubles, okay, a bit over the top)
+
+ DegreesCelsius = "celsius",
+ DegreesFahrenheit = "fahrenheit",
+ DegreeCelsius = "celsius",
+ DegreeFahrenheit = "fahrenheit",
+
+ ["Degrees Celsius"] = "celsius",
+ ["Degrees Fahrenheit"] = "fahrenheit",
+ ["Degree Celsius"] = "celsius",
+ ["Degree Fahrenheit"] = "fahrenheit",
+
+ -- too late as we already have connected symbols catched:
+ --
+ -- ["° Celsius"] = "celsius",
+ -- ["° Fahrenheit"] = "fahrenheit",
+ -- ["°Celsius"] = "celsius",
+ -- ["°Fahrenheit"] = "fahrenheit",
+
+ -- the "natural units" and "atomic units" are omitted for now
+ -- synonyms
+
+ eV = "electronvolt",
+ AMU = "atomicmassunit",
+
+ -- other non-SI units (Table 8)
+
+ Bar = "bar",
+ Hg = "mercury",
+ -- ["Millimetre Of Mercury"] = [[mmHg]],
+ Angstrom = "angstrom", -- strictly Ångström
+ NauticalMile = "nauticalmile",
+ Barn = "barn",
+ Knot = "knot",
+ Neper = "neper",
+ Bel = "bel", -- in practice only decibel used
+
+ ["Nautical Mile"] = "nauticalmile",
+
+ -- other non-SI units from CGS system (Table 9)
+
+ Erg = "erg",
+ Dyne = "dyne",
+ Poise = "poise",
+ Stokes = "stokes",
+ Stilb = "stilb",
+ Phot = "phot",
+ Gal = "gal",
+ Maxwell = "maxwell",
+ Gauss = "gauss",
+ Oersted = "oersted",
+
+ -- end of SI
+
+ -- data: for use with the binary prefixes (except Erlang)
+
+ Bit = "bit",
+ Byte = "byte" ,
+ Baud = "baud",
+ Erlang = "erlang",
+
+ -- common units, not part of SI
+
+ Atmosphere = "atmosphere",
+ Revolution = "revolution",
+
+ -- synonyms
+
+ Atm = "atmosphere",
+ Rev = "revolution",
+
+ -- imperial units (very incomplete)
+
+ Fahrenheit = "fahrenheit",
+ Foot = "foot",
+ Inch = "inch",
+ Calorie = "calorie",
+
+ -- synonyms
+
+ Cal = "calorie",
+
+}
+
+local long_operators = {
+
+ Times = "times",
+ Solidus = "solidus",
+ Per = "per",
+ OutOf = "outof",
+
+}
+
+local long_suffixes = {
+
+ Linear = "linear",
+ Square = "square",
+ Cubic = "cubic",
+ Quadratic = "quadratic",
+ Inverse = "inverse",
+ ILinear = "ilinear",
+ ISquare = "isquare",
+ ICubic = "icubic",
+ IQuadratic = "iquadratic",
+
+}
+
+local short_prefixes = {
+
+ y = "yocto",
+ z = "zetto",
+ a = "atto",
+ f = "femto",
+ p = "pico",
+ n = "nano",
+ u = "micro",
+ m = "milli",
+ c = "centi",
+ d = "deci",
+ da = "deca",
+ h = "hecto",
+ k = "kilo",
+ M = "mega",
+ G = "giga",
+ T = "tera",
+ P = "peta",
+ E = "exa",
+ Z = "zetta",
+ Y = "yotta",
+
+}
+
+local short_units = { -- I'm not sure about casing
+
+ m = "meter",
+ Hz = "hertz",
+ hz = "hertz",
+ B = "bel",
+ b = "bel",
+ lx = "lux",
+ -- da = "dalton",
+ h = "hour",
+ s = "second",
+ g = "gram",
+ n = "newton",
+ v = "volt",
+ t = "tonne",
+ l = "liter",
+ -- w = "watt",
+ W = "watt",
+ -- a = "ampere",
+ A = "ampere",
+
+-- C = "coulomb", -- needs checking with (c)enti
+-- K = "kelvin", -- needs checking with (k)ilo
+-- N = "newton", -- needs checking with (n)ewton
+
+ min = "minute",
+
+ [utfchar(0x2103)] = "celsius",
+ [utfchar(0x2109)] = "fahrenheit",
+}
+
+local short_operators = {
+ ["."] = "times",
+ ["*"] = "times",
+ ["/"] = "solidus",
+ [":"] = "outof",
+}
+
+local short_suffixes = { -- maybe just raw digit match
+ ["1"] = "linear",
+ ["2"] = "square",
+ ["3"] = "cubic",
+ ["4"] = "quadratic",
+ ["+1"] = "linear",
+ ["+2"] = "square",
+ ["+3"] = "cubic",
+ ["+4"] = "quadratic",
+ ["-1"] = "inverse",
+ ["-1"] = "ilinear",
+ ["-2"] = "isquare",
+ ["-3"] = "icubic",
+ ["-4"] = "iquadratic",
+ ["^1"] = "linear",
+ ["^2"] = "square",
+ ["^3"] = "cubic",
+ ["^4"] = "quadratic",
+ ["^+1"] = "linear",
+ ["^+2"] = "square",
+ ["^+3"] = "cubic",
+ ["^+4"] = "quadratic",
+ ["^-1"] = "inverse",
+ ["^-1"] = "ilinear",
+ ["^-2"] = "isquare",
+ ["^-3"] = "icubic",
+ ["^-4"] = "iquadratic",
+}
+
+local symbol_units = {
+ Degrees = "degree",
+ Degree = "degree",
+ -- Deg = "degree",
+ ["°"] = "degree",
+ ArcMinute = "arcminute",
+ ["′"] = "arcminute", -- 0x2032
+ ArcSecond = "arcsecond",
+ ["″"] = "arcsecond", -- 0x2033
+ Percent = "percent",
+ ["%"] = "percent",
+ Promille = "permille",
+ Permille = "permille",
+}
+
+local packaged_units = {
+ Micron = "micron",
+ mmHg = "millimetermercury",
+}
+
+-- rendering:
+
+local ctx_unitsPUS = context.unitsPUS
+local ctx_unitsPU = context.unitsPU
+local ctx_unitsPS = context.unitsPS
+local ctx_unitsP = context.unitsP
+local ctx_unitsUS = context.unitsUS
+local ctx_unitsU = context.unitsU
+local ctx_unitsS = context.unitsS
+local ctx_unitsO = context.unitsO
+local ctx_unitsN = context.unitsN
+local ctx_unitsC = context.unitsC
+local ctx_unitsQ = context.unitsQ
+local ctx_unitsRPM = context.unitsRPM
+local ctx_unitsRTO = context.unitsRTO
+local ctx_unitsRabout = context.unitsRabout
+local ctx_unitsNstart = context.unitsNstart
+local ctx_unitsNstop = context.unitsNstop
+local ctx_unitsNspace = context.unitsNspace
+local ctx_unitsPopen = context.unitsPopen
+local ctx_unitsPclose = context.unitsPclose
+
+local labels = languages.data.labels
+
+labels.prefixes = allocate {
+ yocto = { labels = { en = [[y]] } }, -- 10^{-24}
+ zepto = { labels = { en = [[z]] } }, -- 10^{-21}
+ atto = { labels = { en = [[a]] } }, -- 10^{-18}
+ femto = { labels = { en = [[f]] } }, -- 10^{-15}
+ pico = { labels = { en = [[p]] } }, -- 10^{-12}
+ nano = { labels = { en = [[n]] } }, -- 10^{-9}
+ micro = { labels = { en = [[\mu]] } }, -- 10^{-6}
+ milli = { labels = { en = [[m]] } }, -- 10^{-3}
+ centi = { labels = { en = [[c]] } }, -- 10^{-2}
+ deci = { labels = { en = [[d]] } }, -- 10^{-1}
+ deca = { labels = { en = [[da]] } }, -- 10^{1}
+ hecto = { labels = { en = [[h]] } }, -- 10^{2}
+ kilo = { labels = { en = [[k]] } }, -- 10^{3}
+ mega = { labels = { en = [[M]] } }, -- 10^{6}
+ giga = { labels = { en = [[G]] } }, -- 10^{9}
+ tera = { labels = { en = [[T]] } }, -- 10^{12}
+ peta = { labels = { en = [[P]] } }, -- 10^{15}
+ exa = { labels = { en = [[E]] } }, -- 10^{18}
+ zetta = { labels = { en = [[Z]] } }, -- 10^{21}
+ yotta = { labels = { en = [[Y]] } }, -- 10^{24}
+ kibi = { labels = { en = [[Ki]] } }, -- 2^{10} (not ki)
+ mebi = { labels = { en = [[Mi]] } }, -- 2^{20}
+ gibi = { labels = { en = [[Gi]] } }, -- 2^{30}
+ tebi = { labels = { en = [[Ti]] } }, -- 2^{40}
+ pebi = { labels = { en = [[Pi]] } }, -- 2^{50}
+ exbi = { labels = { en = [[Ei]] } }, -- 2^{60}
+ zebi = { labels = { en = [[Zi]] } }, -- binary
+ yobi = { labels = { en = [[Yi]] } }, -- binary
+ micro = { labels = { en = [[µ]] } }, -- 0x00B5 \textmu
+ root = { labels = { en = [[√]] } }, -- 0x221A
+}
+
+labels.units = allocate {
+ meter = { labels = { en = [[m]] } },
+ gram = { labels = { en = [[g]] } }, -- strictly kg is the base unit
+ second = { labels = { en = [[s]] } },
+ ampere = { labels = { en = [[A]] } },
+ kelvin = { labels = { en = [[K]] } },
+ mole = { labels = { en = [[mol]] } },
+ candela = { labels = { en = [[cd]] } },
+ mol = { labels = { en = [[mol]] } },
+ radian = { labels = { en = [[rad]] } },
+ steradian = { labels = { en = [[sr]] } },
+ hertz = { labels = { en = [[Hz]] } },
+ newton = { labels = { en = [[N]] } },
+ pascal = { labels = { en = [[Pa]] } },
+ joule = { labels = { en = [[J]] } },
+ watt = { labels = { en = [[W]] } },
+ coulomb = { labels = { en = [[C]] } },
+ volt = { labels = { en = [[V]] } },
+ farad = { labels = { en = [[F]] } },
+ ohm = { labels = { en = [[Ω]] } }, -- 0x2126 \textohm
+ siemens = { labels = { en = [[S]] } },
+ weber = { labels = { en = [[Wb]] } },
+ mercury = { labels = { en = [[Hg]] } },
+ millimetermercury = { labels = { en = [[mmHg]] } }, -- connected
+ tesla = { labels = { en = [[T]] } },
+ henry = { labels = { en = [[H]] } },
+ celsius = { labels = { en = [[\checkedtextcelsius]] } }, -- 0x2103
+ lumen = { labels = { en = [[lm]] } },
+ lux = { labels = { en = [[lx]] } },
+ becquerel = { labels = { en = [[Bq]] } },
+ gray = { labels = { en = [[Gy]] } },
+ sievert = { labels = { en = [[Sv]] } },
+ katal = { labels = { en = [[kat]] } },
+ minute = { labels = { en = [[min]] } },
+ hour = { labels = { en = [[h]] } },
+ day = { labels = { en = [[d]] } },
+ gon = { labels = { en = [[gon]] } },
+ grad = { labels = { en = [[grad]] } },
+ hectare = { labels = { en = [[ha]] } },
+ liter = { labels = { en = [[l]] } }, -- symbol l or L
+ tonne = { labels = { en = [[t]] } },
+ electronvolt = { labels = { en = [[eV]] } },
+ dalton = { labels = { en = [[Da]] } },
+ atomicmassunit = { labels = { en = [[u]] } },
+ astronomicalunit = { labels = { en = [[au]] } },
+ bar = { labels = { en = [[bar]] } },
+ angstrom = { labels = { en = [[Å]] } }, -- strictly Ångström
+ nauticalmile = { labels = { en = [[M]] } },
+ barn = { labels = { en = [[b]] } },
+ knot = { labels = { en = [[kn]] } },
+ neper = { labels = { en = [[Np]] } },
+ bel = { labels = { en = [[B]] } }, -- in practice only decibel used
+ erg = { labels = { en = [[erg]] } },
+ dyne = { labels = { en = [[dyn]] } },
+ poise = { labels = { en = [[P]] } },
+ stokes = { labels = { en = [[St]] } },
+ stilb = { labels = { en = [[sb]] } },
+ phot = { labels = { en = [[phot]] } },
+ gal = { labels = { en = [[gal]] } },
+ maxwell = { labels = { en = [[Mx]] } },
+ gauss = { labels = { en = [[G]] } },
+ oersted = { labels = { en = [[Oe]] } }, -- strictly Œrsted
+ bit = { labels = { en = [[bit]] } },
+ byte = { labels = { en = [[B]] } },
+ baud = { labels = { en = [[Bd]] } },
+ erlang = { labels = { en = [[E]] } },
+ atmosphere = { labels = { en = [[atm]] } },
+ revolution = { labels = { en = [[rev]] } },
+ fahrenheit = { labels = { en = [[\checkedtextfahrenheit]] } }, -- 0x2109
+ foot = { labels = { en = [[ft]] } },
+ inch = { labels = { en = [[inch]] } },
+ calorie = { labels = { en = [[cal]] } },
+ --
+ degree = { labels = { en = [[°]]} },
+ arcminute = { labels = { en = [[\checkedtextprime]] } }, -- ′ 0x2032
+ arcsecond = { labels = { en = [[\checkedtextdoubleprime]] } }, -- ″ 0x2033
+ percent = { labels = { en = [[\percent]] } },
+ permille = { labels = { en = [[\promille]] } },
+ --
+ micron = { labels = { en = [[\textmu m]] } },
+}
+
+labels.operators = allocate {
+ times = { labels = { en = [[\unitsTIMES]] } },
+ solidus = { labels = { en = [[\unitsSOLIDUS]] } },
+ per = { labels = { en = [[\unitsSOLIDUS]] } },
+ outof = { labels = { en = [[\unitsOUTOF]] } },
+}
+
+labels.suffixes = allocate {
+ linear = { labels = { en = [[1]] } },
+ square = { labels = { en = [[2]] } },
+ cubic = { labels = { en = [[3]] } },
+ quadratic = { labels = { en = [[4]] } },
+ inverse = { labels = { en = [[\mathminus1]] } },
+ ilinear = { labels = { en = [[\mathminus1]] } },
+ isquare = { labels = { en = [[\mathminus2]] } },
+ icubic = { labels = { en = [[\mathminus3]] } },
+ iquadratic = { labels = { en = [[\mathminus4]] } },
+}
+
+local function dimpus(p,u,s)
+ if trace_units then
+ report_units("prefix %a, unit %a, suffix %a",p,u,s)
+ end --
+ if p ~= "" then
+ if u ~= "" then
+ if s ~= "" then
+ ctx_unitsPUS(p,u,s)
+ else
+ ctx_unitsPU(p,u)
+ end
+ elseif s ~= "" then
+ ctx_unitsPS(p,s)
+ else
+ ctx_unitsP(p)
+ end
+ else
+ if u ~= "" then
+ if s ~= "" then
+ ctx_unitsUS(u,s)
+ -- elseif c then
+ -- ctx_unitsC(u)
+ else
+ ctx_unitsU(u)
+ end
+ elseif s ~= "" then
+ ctx_unitsS(s)
+ else
+ ctx_unitsP(p)
+ end
+ end
+end
+
+local function dimspu(s,p,u)
+ return dimpus(p,u,s)
+end
+
+local function dimop(o)
+ if trace_units then
+ report_units("operator %a",o)
+ end
+ if o then
+ ctx_unitsO(o)
+ end
+end
+
+local function dimsym(s)
+ if trace_units then
+ report_units("symbol %a",s)
+ end
+ s = symbol_units[s] or s
+ if s then
+ ctx_unitsC(s)
+ end
+end
+
+local function dimpre(p)
+ if trace_units then
+ report_units("prefix [%a",p)
+ end
+ p = packaged_units[p] or p
+ if p then
+ ctx_unitsU(p)
+ end
+end
+
+-- patterns:
+--
+-- space inside Cs else funny captures and args to function
+--
+-- square centi meter per square kilo seconds
+
+-- todo 0x -> rm
+
+local function update_parsers(keepcase) -- todo: don't remap utf sequences
+
+ local all_long_prefixes = { }
+ local all_long_units = { }
+ local all_long_operators = { }
+ local all_long_suffixes = { }
+ local all_symbol_units = { }
+ local all_packaged_units = { }
+
+ local all_short_prefixes = { }
+ local all_short_units = { }
+ local all_short_operators = { }
+ local all_short_suffixes = { }
+
+ for k, v in sortedhash(long_prefixes) do all_long_prefixes [k] = v all_long_prefixes [lower(k)] = v end
+ for k, v in sortedhash(long_units) do all_long_units [k] = v all_long_units [lower(k)] = v end
+ for k, v in sortedhash(long_operators) do all_long_operators[k] = v all_long_operators[lower(k)] = v end
+ for k, v in sortedhash(long_suffixes) do all_long_suffixes [k] = v all_long_suffixes [lower(k)] = v end
+ for k, v in sortedhash(symbol_units) do all_symbol_units [k] = v all_symbol_units [lower(k)] = v end
+ for k, v in sortedhash(packaged_units) do all_packaged_units[k] = v all_packaged_units[lower(k)] = v end
+
+ for k, v in sortedhash(user_long_prefixes) do all_long_prefixes [k] = v if not keepcase then all_long_prefixes [lower(k)] = v end end
+ for k, v in sortedhash(user_long_units) do all_long_units [k] = v if not keepcase then all_long_units [lower(k)] = v end end
+ for k, v in sortedhash(user_long_operators) do all_long_operators[k] = v if not keepcase then all_long_operators[lower(k)] = v end end
+ for k, v in sortedhash(user_long_suffixes) do all_long_suffixes [k] = v if not keepcase then all_long_suffixes [lower(k)] = v end end
+ for k, v in sortedhash(user_symbol_units) do all_symbol_units [k] = v if not keepcase then all_symbol_units [lower(k)] = v end end
+ for k, v in sortedhash(user_packaged_units) do all_packaged_units[k] = v if not keepcase then all_packaged_units[lower(k)] = v end end
+
+ for k, v in sortedhash(short_prefixes) do all_short_prefixes [k] = v end
+ for k, v in sortedhash(short_units) do all_short_units [k] = v end
+ for k, v in sortedhash(short_operators) do all_short_operators[k] = v end
+ for k, v in sortedhash(short_suffixes) do all_short_suffixes [k] = v end
+
+ for k, v in sortedhash(user_short_prefixes) do all_short_prefixes [k] = v end
+ for k, v in sortedhash(user_short_units) do all_short_units [k] = v end
+ for k, v in sortedhash(user_short_operators) do all_short_operators[k] = v end
+ for k, v in sortedhash(user_short_suffixes) do all_short_suffixes [k] = v end
+
+ local somespace = P(" ")^0/""
+
+ local p_long_prefix = appendlpeg(all_long_prefixes,nil,true)
+ local p_long_unit = appendlpeg(all_long_units,nil,true)
+ local p_long_operator = appendlpeg(all_long_operators,nil,true)
+ local p_long_suffix = appendlpeg(all_long_suffixes,nil,true)
+ local p_symbol = appendlpeg(all_symbol_units,nil,true)
+ local p_packaged = appendlpeg(all_packaged_units,nil,true)
+
+ local p_short_prefix = appendlpeg(all_short_prefixes)
+ local p_short_unit = appendlpeg(all_short_units)
+ local p_short_operator = appendlpeg(all_short_operators)
+ local p_short_suffix = appendlpeg(all_short_suffixes)
+
+ -- more efficient but needs testing
+
+-- local p_long_prefix = utfchartabletopattern(all_long_prefixes) / all_long_prefixes
+-- local p_long_unit = utfchartabletopattern(all_long_units) / all_long_units
+-- local p_long_operator = utfchartabletopattern(all_long_operators) / all_long_operators
+-- local p_long_suffix = utfchartabletopattern(all_long_suffixes) / all_long_suffixes
+-- local p_symbol = utfchartabletopattern(all_symbol_units) / all_symbol_units
+-- local p_packaged = utfchartabletopattern(all_packaged_units) / all_packaged_units
+
+-- local p_short_prefix = utfchartabletopattern(all_short_prefixes) / all_short_prefixes
+-- local p_short_unit = utfchartabletopattern(all_short_units) / all_short_units
+-- local p_short_operator = utfchartabletopattern(all_short_operators) / all_short_operators
+-- local p_short_suffix = utfchartabletopattern(all_short_suffixes) / all_short_suffixes
+
+ -- we can can cleanup some space issues here (todo)
+
+ local unitparser = P { "unit",
+ --
+ longprefix = Cs(V("somespace") * p_long_prefix),
+ shortprefix = Cs(V("somespace") * p_short_prefix),
+ longsuffix = Cs(V("somespace") * p_long_suffix),
+ shortsuffix = Cs(V("somespace") * p_short_suffix),
+ shortunit = Cs(V("somespace") * p_short_unit),
+ longunit = Cs(V("somespace") * p_long_unit),
+ longoperator = Cs(V("somespace") * p_long_operator),
+ shortoperator = Cs(V("somespace") * p_short_operator),
+ packaged = Cs(V("somespace") * p_packaged),
+ --
+ nothing = Cc(""),
+ somespace = somespace,
+ nospace = (1-somespace)^1, -- was 0
+ -- ignore = P(-1),
+ --
+ qualifier = Cs(V("somespace") * (lparent/"") * (1-rparent)^1 * (rparent/"")),
+ --
+ somesymbol = V("somespace")
+ * (p_symbol/dimsym)
+ * V("somespace"),
+ somepackaged = V("somespace")
+ * (V("packaged") / dimpre)
+ * V("somespace"),
+ -- someunknown = V("somespace")
+ -- * (V("nospace")/ctx_unitsU)
+ -- * V("somespace"),
+ --
+ combination = V("longprefix") * V("longunit") -- centi meter
+ + V("nothing") * V("longunit")
+ + V("shortprefix") * V("shortunit") -- c m
+ + V("nothing") * V("shortunit")
+ + V("longprefix") * V("shortunit") -- centi m
+ + V("shortprefix") * V("longunit"), -- c meter
+
+-- combination = ( V("longprefix") -- centi meter
+-- + V("nothing")
+-- ) * V("longunit")
+-- + ( V("shortprefix") -- c m
+-- + V("nothing")
+-- + V("longprefix")
+-- ) * V("shortunit") -- centi m
+-- + ( V("shortprefix") -- c meter
+-- ) * V("longunit"),
+
+
+ dimension = V("somespace")
+ * (
+ V("packaged") / dimpre
+ + (V("longsuffix") * V("combination")) / dimspu
+ + (V("combination") * (V("shortsuffix") + V("nothing"))) / dimpus
+ )
+ * (V("qualifier") / ctx_unitsQ)^-1
+ * V("somespace"),
+ operator = V("somespace")
+ * ((V("longoperator") + V("shortoperator")) / dimop)
+ * V("somespace"),
+ snippet = V("dimension")
+ + V("somesymbol"),
+ unit = ( V("snippet") * (V("operator") * V("snippet"))^0
+ + V("somepackaged")
+ )^1,
+ }
+
+ -- todo: avoid \ctx_unitsNstart\ctx_unitsNstop (weird that it can happen .. now catched at tex end)
+
+ local letter = R("az","AZ")
+ local bound = #(1-letter)
+ -- local number = lpeg.patterns.number
+ local number = Cs( P("$") * (1-P("$"))^1 * P("$")
+ + P([[\m{]]) * (1-P("}"))^1 * P("}")
+ + (1-letter-P(" "))^1 -- todo: catch { } -- not ok
+ ) / ctx_unitsN
+
+ local start = Cc(nil) / ctx_unitsNstart
+ local stop = Cc(nil) / ctx_unitsNstop
+ local space = P(" ") * Cc(nil) / ctx_unitsNspace
+ local open = P("(") * Cc(nil) / ctx_unitsPopen
+ local close = P(")") * Cc(nil) / ctx_unitsPclose
+
+ local range = somespace
+ * ( (P("±") + P("pm") * bound) / "" / ctx_unitsRPM
+ + (P("–") + P("to") * bound) / "" / ctx_unitsRTO )
+ * somespace
+
+ local about = (P("±") + P("pm") * bound) / "" / ctx_unitsRabout
+ * somespace
+
+ -- todo: start / stop
+
+ local function combine(parser)
+ return P { "start",
+ number = start * dleader * (parser + number) * stop,
+ anumber = space
+ * open
+ * V("about")^-1
+ * V("number")
+ * close,
+ rule = V("number")^-1
+ * (V("range") * V("number") + V("anumber"))^-1,
+ unit = unitparser,
+ about = about,
+ range = range,
+ space = space,
+ start = V("rule")
+ * V("unit")
+ * (V("space") * V("rule") * V("unit"))^0
+ + open
+ * V("number")
+ * (V("range") * V("number"))^-1
+ * close
+ * dtrailer^-1
+ * V("unit")
+ + V("number")
+ }
+ end
+
+ return combine(p_c_dparser), combine(c_p_dparser)
+end
+
+local p_c_parser_lowercase = nil
+local c_p_parser_lowercase = nil
+local p_c_parser_keepcase = nil
+local c_p_parser_keepcase = nil
+
+local dirty_lowercase = true
+local dirty_keepcase = true
+
+local v_reverse = interfaces.variables.reverse
+local v_keep = interfaces.variables.keep
+
+local function makeunit(order,option,str)
+ local reverse = order == v_reverse
+ local keep = option == v_keep
+ local parser
+ if keep then
+ if dirty_keepcase then
+ if trace_units then
+ report_units("initializing case %s parser","sensititive")
+ end
+ p_c_parser_keepcase, c_p_parser_keepcase = update_parsers(true)
+ dirty_keepcase = false
+ end
+ parser = reverse and p_c_parser_keepcase or c_p_parser_keepcase
+ else
+ if dirty_lowercase then
+ if trace_units then
+ report_units("initializing case %s parser","insensititive")
+ end
+ p_c_parser_lowercase, c_p_parser_lowercase = update_parsers()
+ dirty_lowercase = false
+ end
+ parser = reverse and p_c_parser_lowercase or c_p_parser_lowercase
+ end
+ if not matchlpeg(parser,str) then
+ report_units("unable to parse: %s",str)
+ context(str)
+ end
+end
+
+local function trigger(t,k,v)
+ rawset(t,k,v)
+ dirty_lowercase = true
+ dirty_keepcase = true
+end
+
+local t_units = {
+ prefixes = setmetatablenewindex(long_prefixes,trigger),
+ units = setmetatablenewindex(long_units,trigger),
+ operators = setmetatablenewindex(long_operators,trigger),
+ suffixes = setmetatablenewindex(long_suffixes,trigger),
+ symbols = setmetatablenewindex(symbol_units,trigger),
+ packaged = setmetatablenewindex(packaged_units,trigger),
+}
+
+local t_shortcuts = {
+ prefixes = setmetatablenewindex(short_prefixes,trigger),
+ units = setmetatablenewindex(short_units,trigger),
+ operators = setmetatablenewindex(short_operators,trigger),
+ suffixes = setmetatablenewindex(short_suffixes,trigger),
+}
+
+local t_userunits = {
+ prefixes = setmetatablenewindex(user_long_prefixes,trigger),
+ units = setmetatablenewindex(user_long_units,trigger),
+ operators = setmetatablenewindex(user_long_operators,trigger),
+ suffixes = setmetatablenewindex(user_long_suffixes,trigger),
+ symbols = setmetatablenewindex(user_symbol_units,trigger),
+ packaged = setmetatablenewindex(user_packaged_units,trigger),
+}
+
+local t_usershortcuts = {
+ prefixes = setmetatablenewindex(user_short_prefixes,trigger),
+ units = setmetatablenewindex(user_short_units,trigger),
+ operators = setmetatablenewindex(user_short_operators,trigger),
+ suffixes = setmetatablenewindex(user_short_suffixes,trigger),
+}
+
+physics.units.tables = allocate {
+ units = t_units,
+ shortcuts = t_shortcuts,
+ userunits = t_userunits,
+ usershortcuts = t_usershortcuts,
+}
+
+local mapping = {
+ prefix = "prefixes",
+ unit = "units",
+ operator = "operators",
+ suffix = "suffixes",
+ symbol = "symbols",
+ packaged = "packaged",
+}
+
+local function register(category,list,target)
+ if not list or list == "" then
+ list = category
+ category = "unit"
+ end
+ local t = target[mapping[category]]
+ if t then
+ for k, v in next, utilities.parsers.settings_to_hash(list or "") do
+ t[k] = v
+ end
+ end
+ -- inspect(tables)
+end
+
+local function registerunit (category,list) register(category,list,t_userunits) end
+local function registershortcut(category,list) register(category,list,t_usershortcuts) end
+
+physics.units.registerunit = registerunit
+physics.units.registershortcut = registershortcut
+
+implement {
+ name = "digits_normal",
+ actions = makedigits,
+ arguments = "string",
+}
+
+implement {
+ name = "digits_reverse",
+ actions = makedigits,
+ arguments = { "string", true },
+}
+
+implement {
+ name = "unit",
+ actions = makeunit,
+ arguments = "3 strings"
+}
+
+implement {
+ name = "registerunit",
+ actions = registerunit,
+ arguments = "2 strings",
+}
+
+implement {
+ name = "registerunitshortcut",
+ actions = registershortcut,
+ arguments = "2 strings",
+}
+
+implement {
+ name = "hyphenateddigits",
+ public = true,
+ protected = true,
+ arguments = { "optional", "string" },
+ actions = function(filler, digits)
+ digits = gsub(digits,"(%d)","%1\\digitsbreak ") -- space needed for following letters
+ digits = gsub(digits,"\\-$",filler)
+ context(digits)
+ end
+}