UNPKG

@thi.ng/units

Version:

Extensible SI unit creation, conversions, quantities & calculations (incl. List-like DSL and ~170 predefined units & constants)

59 lines (58 loc) 1.71 kB
import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { parse } from "@thi.ng/sexpr/parse"; import { runtime } from "@thi.ng/sexpr/runtime"; import * as CONST from "./constants/index.js"; import { add, asUnit, convert, div, mul, quantity, Quantity, reciprocal, sub } from "./unit.js"; const __mathOp = (fn, fn1) => (first, ...args) => { return args.length > 0 ? ( // use a reduction for 2+ args args.reduce((acc, x) => fn(acc, x), first) ) : ( // apply special case unary function fn1(first) ); }; const ENV = { "+": __mathOp(add, (x) => x), "-": __mathOp(sub, (x) => sub(quantity(0, x.value), x)), "*": __mathOp(mul, (x) => x), "/": __mathOp(div, reciprocal), area: (src) => { const [w, h] = src.value.map((x) => quantity(1, x)); return mul(w, h); }, volume: (src) => { const [w, h, d] = src.value.map((x) => quantity(1, x)); return mul(mul(w, h), d); }, width: (src) => quantity(1, src.value[0]), height: (src) => quantity(1, src.value[1]), depth: (src) => quantity(1, src.value[2]) }; const interpret = runtime({ expr: ({ children: [x, ...args] }) => { const name = x.value; const $args = args.map((a) => interpret(a, null)); return ENV[name]?.apply(null, $args) ?? convert($args[0], asUnit(name)); }, sym: ({ value }) => { const match = /^[-+]?[0-9.]+(e[+-]?\d+)?/.exec(value); return match ? quantity(+match[0], asUnit(value.substring(match[0].length))) : CONST[value.toUpperCase()] ?? asUnit(value); }, str: () => illegalArgs("string value"), num: (x) => x.value }); const $eval = (src) => parse(src).children.reduce((_, x) => interpret(x, null), null); export { $eval };