Calculations
Evaluate mixed unit math without turning lingo into a CAS.
Prefer the live demos? Open this section in the interactive docs.
Arithmetic over quantities lives in @pascal-app/lingo/calc. lingo() never evaluates expressions — mixed-unit compounds like 2 ft + 3 in stay compounds, 5-10 kg stays a range, and 2+3 kg is trailing input rather than a silent 2–3 kg range. calc() is a closed calculator: no variables, no functions, no dimensional algebra.
import { calc } from "@pascal-app/lingo/calc"
import { quantityField } from "@pascal-app/lingo/ai"
import { completions } from "@pascal-app/lingo/complete"
const million = calc("7m*2")
million.ok && million.value // 14000000
million.ok && million.format({ style: "words" }) // "14 million"
million.ok && million.format({ style: "grouped" }) // "14,000,000"
million.ok && million.format({ style: "scientific" }) // "14e6"
million.ok && million.format({ style: "compact" }) // "14m"
million.ok && million.expression // "7e6 × 2"
million.ok && million.latex // "7 \\times 10^{6} \\times 2"
const duration = calc("9min x 4")
duration.ok && duration.format() // "36 min"
duration.ok && duration.format({ unit: "h" }) // "0.6 h"
calc("half of 56kg+1700g") // 28.85 kg
quantityField({ kind: "mass", unit: "kg", calc }).parse("12 * 0.75 kg") // 9
completions("=2+3 kg", { calc: (text) => calc(text, { trigger: "=" }) })Glued m/M at an operator boundary is million (7m*2 → 14 million) unless kind is length or duration; spaced 7 m is meters; 1m80 stays 1.80 m. Compact "14m" round-trips through calc(), not lingo(). Same-kind q / q cancels to a dimensionless ratio; q * q is SCALAR_EXPECTED. Additive affine units warn AFFINE_DELTA_ASSUMED and delta-convert. formatExpression is two-way infix; formatLatex is display-only.
Inject calc into completions({ calc }) and quantityField({ calc }) so =2+3 kg and 12 * 0.75 kg evaluate without bundling the calculator into those entries. Completions only fire on a leading =, so 5-10 kg is not stolen. rangeField stays range-first.