exprify 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -33
- package/dist/exprify.cjs.js +671 -4
- package/dist/exprify.cjs.js.map +1 -1
- package/dist/exprify.esm.js +671 -4
- package/dist/exprify.esm.js.map +1 -1
- package/dist/exprify.js +672 -5
- package/dist/exprify.js.map +1 -1
- package/dist/exprify.min.js +2 -2
- package/dist/exprify.min.js.map +1 -1
- package/package.json +1 -1
- package/src/core/Exprify.js +231 -2
- package/src/function/internal.js +342 -0
- package/src/parser/astBuild.js +24 -1
- package/src/parser/evaluator.js +31 -1
- package/src/utils/matrix.js +53 -0
- package/.gitattributes +0 -2
- package/.github/workflows/ci.yml +0 -40
- package/.github/workflows/npm-publish.yml +0 -38
- package/.github/workflows/security-audit.yml +0 -34
- package/CHANGELOG.md +0 -11
- package/doc/tokenType.txt +0 -48
- package/rollup.config.js +0 -80
- package/test/browser.html +0 -23
- package/test/exprify.test.js +0 -140
package/dist/exprify.min.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/*! exprify v1.0.
|
|
2
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Exprify=t()}(this,function(){"use strict";function e(t,r={}){const n=r.variables,o=r.functions,i=r.units,a=e=>e&&"object"==typeof e&&"value"in e&&"unit"in e,s=e=>e&&"object"==typeof e&&"re"in e&&"im"in e,l=e=>Array.isArray(e)&&e.length>0&&e.every(Array.isArray),u=e=>{if(l(e))return e.map(e=>[...e]);if(Array.isArray(e))return[e];throw new Error("Expected matrix-compatible value")},m=e=>{if("number"!=typeof e||!Number.isInteger(e)||e<1)throw new Error("Matrix indices must be positive integers");return e-1},c=(t,n)=>{if((o=t)&&"object"==typeof o&&"SliceExpression"===o.type){const o=null==t.start?1:e(t.start,r),i=null==t.end?n:e(t.end,r),a=m(o),s=m(i);if(s<a)return[];const l=[];for(let e=a;e<=s;e++)l.push(e);return l}var o;return[m(e(t,r))]},p=e=>{if(s(e))return e;if("number"==typeof e)return{re:e,im:0};throw new Error("Complex arithmetic only supports numbers")},y=e=>0===e.im?e.re:e;switch(t.type){case"Literal":return t.value;case"ImaginaryLiteral":return{re:0,im:t.value};case"UnitLiteral":return{value:t.value,unit:t.unit};case"Identifier":return n.get(t.name);case"AssignmentExpression":{const o=e(t.right,r);if("Identifier"===t.left.type)return n.set(t.left.name,o),o;if("IndexExpression"===t.left.type&&"Identifier"===t.left.object.type){const e=((e,t,r)=>{const n=l(e)?e.map(e=>[...e]):Array.isArray(e)?[e.slice()]:[],o=t[0],i=t[1];if(!o)throw new Error("Matrix assignment requires at least one index");const a=Math.max(n.length,1),s=c(o,a);if(1===t.length){const e=l(r)?r:u(r);if(e.length!==s.length)throw new Error("Assigned row count does not match slice");return s.forEach((t,r)=>{n[t]=[...e[r]]}),{updatedMatrix:n,selectionResult:1===s.length?[n[s[0]]]:s.map(e=>[n[e]])}}const m=Math.max(...n.map(e=>e.length),0,1),p=c(i,m),y=u(r);if(y.length!==s.length)throw new Error("Assigned row count does not match matrix slice");return y.forEach((e,t)=>{if(e.length!==p.length)throw new Error("Assigned column count does not match matrix slice")}),s.forEach((e,t)=>{n[e]||(n[e]=[]),p.forEach((r,o)=>{n[e][r]=y[t][o]})}),{updatedMatrix:n,selectionResult:1===s.length?[p.map(e=>n[s[0]][e])]:s.map(e=>p.map(t=>n[e][t]))}})(n.get(t.left.object.name),t.left.selectors,o);return n.set(t.left.object.name,e.updatedMatrix),e.selectionResult}throw new Error("Invalid assignment target")}case"UnaryExpression":{const n=e(t.argument,r);switch(t.operator){case"-":return s(n)?y({re:-n.re,im:-n.im}):-n;case"!":return!n}throw new Error(`Unknown unary operator ${t.operator}`)}case"BinaryExpression":{let n=e(t.left,r),o=e(t.right,r);if(a(n)||a(o)){if(!i)throw new Error("Unit system not available");return i.compute(t.operator,n,o)}if("*"===t.operator&&(Array.isArray(n)||Array.isArray(o)))return((e,t)=>{const r=u(e),n=u(t);if(r[0].length!==n.length)throw new Error("Matrix dimensions do not allow multiplication");return r.map(e=>n[0].map((t,r)=>e.reduce((e,t,o)=>e+t*n[o][r],0)))})(n,o);if(s(n)||s(o))return((e,t,r)=>{const n=p(t),o=p(r);switch(e){case"+":return y({re:n.re+o.re,im:n.im+o.im});case"-":return y({re:n.re-o.re,im:n.im-o.im});case"*":return y({re:n.re*o.re-n.im*o.im,im:n.re*o.im+n.im*o.re});case"/":{const e=o.re**2+o.im**2;if(0===e)throw new Error("Division by zero");return y({re:(n.re*o.re+n.im*o.im)/e,im:(n.im*o.re-n.re*o.im)/e})}default:throw new Error(`Operator ${e} is not supported for complex numbers`)}})(t.operator,n,o);switch(t.operator){case"+":return n+o;case"-":return n-o;case"*":return n*o;case"/":return n/o;case"%":return n%o;case"^":return n**o;case">":return n>o;case"<":return n<o;case">=":return n>=o;case"<=":return n<=o;case"==":return n===o}throw new Error(`Unknown operator ${t.operator}`)}case"LogicalExpression":{const n=e(t.left,r);if("&&"===t.operator)return n&&e(t.right,r);if("||"===t.operator)return n||e(t.right,r);if("??"===t.operator)return n??e(t.right,r);throw new Error(`Unknown logical operator ${t.operator}`)}case"CallExpression":{const n=t.callee.name;return o.get(n)(...t.arguments.map(t=>e(t,r)))}case"PipelineExpression":{const n=e(t.left,r);if("CallExpression"===t.right.type){const i=t.right.callee.name;return o.get(i)(...[n,...t.right.arguments.map(t=>e(t,r))])}if("Identifier"===t.right.type){return o.get(t.right.name)(n)}throw new Error("Invalid pipeline target")}case"UnitConversion":{const n=e(t.from,r);if(!a(n))throw new Error("Left side must be a unit value");if(!i)throw new Error("Unit system not available");return i.convert(n.value,n.unit,t.to)}case"ArrayExpression":return t.elements.map(t=>e(t,r));case"IndexExpression":return((e,t)=>{const r=u(e);if(1===t.length){const e=c(t[0],r.length).map(e=>{if(e>=r.length)throw new Error("Row index out of range");return[...r[e]]});return 1===e.length?e[0]:e}const n=c(t[0],r.length),o=c(t[1],r[0]?.length||0),i=n.map(e=>{if(e>=r.length)throw new Error("Row index out of range");return o.map(t=>{if(t>=r[e].length)throw new Error("Column index out of range");return r[e][t]})});return 1===n.length&&1===o.length?i[0][0]:1===n.length?i[0]:1===o.length?i.map(e=>[e[0]]):i})(e(t.object,r),t.selectors);case"ObjectExpression":{const n={};for(let o of t.properties)n[o.key]=e(o.value,r);return n}case"MemberExpression":{const n=e(t.object,r);if(t.optional&&null==n)return;return n[t.property.name]}default:throw new Error(`Unknown AST node type: ${t.type}`)}}function t({variables:e,functions:r,units:n,evaluate:o}){if(!e)throw new Error("Variable store missing");if(!r)throw new Error("Function registry missing");if(!n)throw new Error("Units list missing");if(!o)throw new Error("evaluate function missing");return{variables:e,functions:r,units:n,evaluate:o,withScope(i={}){const a={...e.all?.(),...i};return t({functions:r,evaluate:o,units:n,variables:{get:e=>a[e],set:(e,t)=>a[e]=t,all:()=>a}})}}}const r=(e,t)=>typeof e==typeof t&&("number"==typeof e||"bigint"==typeof e),n=Object.freeze({power:function(e,t){if(r(e,t))return e**t;throw new Error("Invalid types for ^")},multiply:function(e,t){if(r(e,t))return e*t;throw new Error("Invalid types for *")},divide:function(e,t){if(r(e,t)){if(0===t)throw new Error("Division by zero");return e/t}throw new Error("Invalid types for /")},add:function(e,t){if(r(e,t))return e+t;if("string"==typeof e&&"string"==typeof t)return e+t;throw new Error("Invalid types for +")},subtract:function(e,t){if(r(e,t))return e-t;throw new Error("Invalid types for -")},modulus:function(e,t){if(r(e,t))return e%t;throw new Error("Invalid types for %")}});const o={length:{m:{value:1,unit:"meter",symbol:"m"},cm:{value:.01,unit:"centimeter",symbol:"cm"},mm:{value:.001,unit:"millimeter",symbol:"mm"},km:{value:1e3,unit:"kilometer",symbol:"km"},um:{value:1e-6,unit:"micrometer",symbol:"um",note:"also called micron"},nm:{value:1e-9,unit:"nanometer",symbol:"nm"},px:{value:264583e-9,unit:"pixel",symbol:"px",note:"96dpi standard"},em:{value:.004233328,unit:"em",symbol:"em",note:"1em = 16px by default"},rem:{value:.004233328,unit:"rem",symbol:"rem",note:"root em = 16px by default"},pt:{value:352778e-9,unit:"point",symbol:"pt",note:"1pt = 1/72 inch"},pc:{value:.00423333,unit:"pica",symbol:"pc",note:"1pc = 12pt"},inch:{value:.0254,unit:"inch",symbol:"in"},ft:{value:.3048,unit:"foot",symbol:"ft"},yd:{value:.9144,unit:"yard",symbol:"yd"},mi:{value:1609.344,unit:"mile",symbol:"mi"},thou:{value:254e-7,unit:"mil",symbol:"thou",note:"thousandth of an inch"},furlong:{value:201.168,unit:"furlong",symbol:"fur",note:"220 yards"},nmi:{value:1852,unit:"nautical mile",symbol:"nmi"},fathom:{value:1.8288,unit:"fathom",symbol:"fathom"},au:{value:1496e8,unit:"astronomical unit",symbol:"AU"},ly:{value:94607e11,unit:"light year",symbol:"ly"},pc:{value:30857e12,unit:"parsec",symbol:"pc"}},weight:{mg:{value:1e-6,unit:"milligram",symbol:"mg"},g:{value:.001,unit:"gram",symbol:"g"},kg:{value:1,unit:"kilogram",symbol:"kg"},t:{value:1e3,unit:"tonne",symbol:"t",note:"metric ton"},lb:{value:.453592,unit:"pound",symbol:"lb"},oz:{value:.0283495,unit:"ounce",symbol:"oz"},stone:{value:6.35029,unit:"stone",symbol:"st",note:"1 stone = 14 lb"}},time:{s:{value:1,unit:"second",symbol:"s"},min:{value:60,unit:"minute",symbol:"min"},h:{value:3600,unit:"hour",symbol:"h"},day:{value:86400,unit:"day",symbol:"d"},week:{value:604800,unit:"week",symbol:"wk"},month:{value:2629800,unit:"month",symbol:"mo",note:"average month = 30.44 days"},year:{value:31557600,unit:"year",symbol:"yr",note:"average year = 365.25 days"}},voltage:{V:{value:1,unit:"volt",symbol:"V"},mV:{value:.001,unit:"millivolt",symbol:"mV"},kV:{value:1e3,unit:"kilovolt",symbol:"kV"},MV:{value:1e6,unit:"megavolt",symbol:"MV"},GV:{value:1e9,unit:"gigavolt",symbol:"GV"},statV:{value:299.792458,unit:"statvolt",symbol:"statV",note:"CGS unit"},abV:{value:1e-8,unit:"abvolt",symbol:"abV",note:"CGS electromagnetic unit"}},frequency:{Hz:{value:1,unit:"hertz",symbol:"Hz",note:"1 cycle per second"},kHz:{value:1e3,unit:"kilohertz",symbol:"kHz"},MHz:{value:1e6,unit:"megahertz",symbol:"MHz"},GHz:{value:1e9,unit:"gigahertz",symbol:"GHz"},THz:{value:1e12,unit:"terahertz",symbol:"THz"}},power:{W:{value:1,unit:"watt",symbol:"W",note:"1 joule per second"},mW:{value:.001,unit:"milliwatt",symbol:"mW"},kW:{value:1e3,unit:"kilowatt",symbol:"kW"},MW:{value:1e6,unit:"megawatt",symbol:"MW"},GW:{value:1e9,unit:"gigawatt",symbol:"GW"},HP:{value:745.7,unit:"horsepower",symbol:"HP",note:"mechanical HP = 745.7 W"},kcal_per_h:{value:1.163,unit:"kilocalorie per hour",symbol:"kcal/h",note:"= 1.163 W"},BTU_per_h:{value:.29307107,unit:"BTU per hour",symbol:"BTU/h",note:"= 0.293 W"}},sound:{dB:{value:1,unit:"decibel",symbol:"dB",note:"logarithmic unit of sound intensity"},dBA:{value:1,unit:"A-weighted decibel",symbol:"dBA",note:"Adjusted for human hearing"},dBC:{value:1,unit:"C-weighted decibel",symbol:"dBC",note:"Flat weighting for high-level sounds"}},temperature:{K:{value:1,unit:"kelvin",symbol:"K"},C:{value:1,unit:"Celsius",symbol:"°C",note:"°C → K: add 273.15"},F:{value:1,unit:"Fahrenheit",symbol:"°F",note:"°F → K: (°F - 32) * 5/9 + 273.15"}},pressure:{Pa:{value:1,unit:"pascal",symbol:"Pa"},kPa:{value:1e3,unit:"kilopascal",symbol:"kPa"},MPa:{value:1e6,unit:"megapascal",symbol:"MPa"},bar:{value:1e5,unit:"bar",symbol:"bar"},atm:{value:101325,unit:"atmosphere",symbol:"atm"},psi:{value:6894.757,unit:"pound per square inch",symbol:"psi"},mmHg:{value:133.322,unit:"millimeter of mercury",symbol:"mmHg"}},energy:{J:{value:1,unit:"joule",symbol:"J"},kJ:{value:1e3,unit:"kilojoule",symbol:"kJ"},cal:{value:4.184,unit:"calorie",symbol:"cal"},kcal:{value:4184,unit:"kilocalorie",symbol:"kcal"},eV:{value:160218e-24,unit:"electronvolt",symbol:"eV"},BTU:{value:1055.06,unit:"BTU",symbol:"BTU"}},force:{N:{value:1,unit:"newton",symbol:"N"},kN:{value:1e3,unit:"kilonewton",symbol:"kN"},lbf:{value:4.44822,unit:"pound-force",symbol:"lbf"},kgf:{value:9.80665,unit:"kilogram-force",symbol:"kgf"},dyne:{value:1e-5,unit:"dyne",symbol:"dyn"}},area:{m2:{value:1,unit:"square meter",symbol:"m²"},cm2:{value:1e-4,unit:"square centimeter",symbol:"cm²"},km2:{value:1e6,unit:"square kilometer",symbol:"km²"},acre:{value:4046.856,unit:"acre",symbol:"acre"},hectare:{value:1e4,unit:"hectare",symbol:"ha"},ft2:{value:.092903,unit:"square foot",symbol:"ft²"},yd2:{value:.836127,unit:"square yard",symbol:"yd²"}},volume:{m3:{value:1,unit:"cubic meter",symbol:"m³"},L:{value:.001,unit:"liter",symbol:"L"},mL:{value:1e-6,unit:"milliliter",symbol:"mL"},gallon:{value:.00378541,unit:"US gallon",symbol:"gal"},pint:{value:473176e-9,unit:"US pint",symbol:"pt"},floz:{value:29574e-9,unit:"US fluid ounce",symbol:"fl oz"}},current:{A:{value:1,unit:"ampere",symbol:"A"},mA:{value:.001,unit:"milliampere",symbol:"mA"},uA:{value:1e-6,unit:"microampere",symbol:"uA"},kA:{value:1e3,unit:"kiloampere",symbol:"kA"}},resistance:{ohm:{value:1,unit:"ohm"},kohm:{value:1e3,unit:"kiloohm"},megaohm:{value:1e6,unit:"megaohm"},S:{value:1,unit:"siemens",symbol:"S",note:"conductance"}},capacitance:{F:{value:1,unit:"farad",symbol:"F"},mF:{value:.001,unit:"millifarad"},uF:{value:1e-6,unit:"microfarad"}},inductance:{H:{value:1,unit:"henry",symbol:"H"},mH:{value:.001,unit:"millihenry",symbol:"mH"},uH:{value:1e-6,unit:"microhenry",symbol:"uH"}},light:{cd:{value:1,unit:"candela",symbol:"cd"},lm:{value:1,unit:"lumen",symbol:"lm"},lx:{value:1,unit:"lux",symbol:"lx"}},data:{bit:{value:1,unit:"bit",symbol:"bit"},B:{value:8,unit:"byte",symbol:"B"},KB:{value:8e3,unit:"kilobyte",symbol:"KB"},MB:{value:8e6,unit:"megabyte",symbol:"MB"},GB:{value:8e9,unit:"gigabyte",symbol:"GB"},TB:{value:8e12,unit:"terabyte",symbol:"TB"}},angle:{deg:{value:1,unit:"degree",symbol:"°"},rad:{value:57.2958,unit:"radian",symbol:"rad",note:"1 rad = 57.2958°"},grad:{value:.9,unit:"grad",symbol:"grad",note:"1 grad = 0.9°"}},radiation:{Gy:{value:1,unit:"gray",symbol:"Gy",note:"Absorbed dose: 1 Gy = 1 J/kg"},mGy:{value:.001,unit:"milligray",symbol:"mGy"},rad:{value:.01,unit:"rad",symbol:"rad",note:"1 rad = 0.01 Gy"},Sv:{value:1,unit:"sievert",symbol:"Sv",note:"Biological effect dose equivalent"},mSv:{value:.001,unit:"millisievert",symbol:"mSv"},rem:{value:.01,unit:"rem",symbol:"rem",note:"1 rem = 0.01 Sv"},Bq:{value:1,unit:"becquerel",symbol:"Bq",note:"1 decay per second"},kBq:{value:1e3,unit:"kilobecquerel",symbol:"kBq"},MBq:{value:1e6,unit:"megabecquerel",symbol:"MBq"},GBq:{value:1e9,unit:"gigabecquerel",symbol:"GBq"},Ci:{value:37e9,unit:"curie",symbol:"Ci",note:"1 Ci = 3.7 x 10¹⁰ decays per second"},mCi:{value:37e6,unit:"millicurie",symbol:"mCi"}}},i=/^[a-zA-Z_$][a-zA-Z0-9_$]*$/;function a(e={}){let t=Object.create(null);for(const r in e)t[r]=e[r];return{set(e,r,{override:n=!0}={}){if("string"!=typeof e||!e)throw new Error("Variable name must be a non-empty string");if(!i.test(e))throw new Error(`Variable Name Error: '${e}' is not a valid variable name`);if(void 0===r)throw new Error(`Variable Value Error: '${e}' cannot be undefined`);if(!n&&e in variablesDB)throw new Error(`Variable '${e}' already exists`);t[e]=r},get:e=>t[e],has:e=>Object.prototype.hasOwnProperty.call(t,e),remove(e){delete t[e]},all:()=>({...t}),clear(){t=Object.create(null)},merge(e={}){for(const r in e)t[r]=e[r]},clone:()=>a(t)}}function s(e){return function(e){if(!Array.isArray(e)||0===e.length)throw new Error("det() expects a non-empty matrix");if(!e.every(Array.isArray))throw new Error("det() expects a 2D matrix");const t=e.length;if(!e.every(e=>e.length===t))throw new Error("det() expects a square matrix");for(const t of e)for(const e of t)if("number"!=typeof e&&"bigint"!=typeof e)throw new Error("det() matrix values must be numeric")}(e),1===e.length?e[0][0]:2===e.length?e[0][0]*e[1][1]-e[0][1]*e[1][0]:e[0].reduce((t,r,n)=>{const o=e.slice(1).map(e=>e.filter((e,t)=>t!==n));return t+(n%2==0?r:-r)*s(o)},0)}function l(e,t){const r=function(e){const t=e.replace(/\s+/g,"");return t?t.replace(/-/g,"+-").split("+").filter(Boolean):[]}(e),n=new Map;for(const e of r)if(e.includes(t)){const[r,o]=e.split(t);let i;if(""===r||"+"===r)i=1;else if("-"===r)i=-1;else{const e=r.endsWith("*")?r.slice(0,-1):r;i=Number(e)}if(!Number.isFinite(i))throw new Error("Unsupported algebra term");let a=1;if(o){if(!o.startsWith("^"))throw new Error("Unsupported algebra term");a=Number(o.slice(1))}if(!Number.isInteger(a)||a<0)throw new Error("Only non-negative integer powers are supported");n.set(a,(n.get(a)||0)+i)}else{const t=Number(e);if(!Number.isFinite(t))throw new Error("Unsupported algebra term");n.set(0,(n.get(0)||0)+t)}return n}function u(e,t){const r=[...e.entries()].filter(([,e])=>0!==e).sort((e,t)=>t[0]-e[0]);return r.length?r.map(([e,r],n)=>{const o=r<0,i=Math.abs(r);let a;return a=0===e?`${i}`:1===e?1===i?t:`${i} * ${t}`:1===i?`${t}^${e}`:`${i} * ${t}^${e}`,0===n?o?`-${a}`:a:o?`- ${a}`:`+ ${a}`}).join(" "):"0"}const m={max:(...e)=>{if(!e.length)throw new Error("max() requires arguments");return Math.max(...e)},min:(...e)=>{if(!e.length)throw new Error("min() requires arguments");return Math.min(...e)},abs:e=>Math.abs(e),round:e=>Math.round(e),floor:e=>Math.floor(e),ceil:e=>Math.ceil(e),sqrt:e=>{if(e<0)throw new Error("sqrt() domain error");return Math.sqrt(e)},pow:(e,t)=>e**t,det:e=>s(e),simplify:e=>{if("string"!=typeof e)throw new Error("simplify() expects an expression string");return function(e){const t=e.replace(/\s+/g,"").match(/[a-zA-Z]+/),r=t?.[0]||"x";return u(l(e,r),r)}(e)},derivative:(e,t="x")=>{if("string"!=typeof e||"string"!=typeof t)throw new Error("derivative() expects expression and variable strings");return function(e,t){const r=l(e,t),n=new Map;for(const[e,t]of r.entries())0!==e&&n.set(e-1,(n.get(e-1)||0)+t*e);return u(n,t)}(e,t)},sin:e=>Math.sin(e),cos:e=>Math.cos(e),tan:e=>Math.tan(e),asin:e=>Math.asin(e),acos:e=>Math.acos(e),atan:e=>Math.atan(e),log:e=>{if(e<=0)throw new Error("log() domain error");return Math.log(e)},log10:e=>{if(e<=0)throw new Error("log10() domain error");return Math.log10(e)},exp:e=>Math.exp(e),random:()=>Math.random(),and:(e,t)=>Boolean(e&&t),or:(e,t)=>Boolean(e||t),not:e=>!e,"!":e=>!e,eq:(e,t)=>e===t,neq:(e,t)=>e!==t,notEqual:(e,t)=>e!==t,gt:(e,t)=>e>t,greaterThan:(e,t)=>e>t,lt:(e,t)=>e<t,lessThan:(e,t)=>e<t,gte:(e,t)=>e>=t,greaterThanOrEqual:(e,t)=>e>=t,lte:(e,t)=>e<=t,lessThanOrEqual:(e,t)=>e<=t,clamp:(e,t,r)=>{if(t>r)throw new Error("clamp(): min > max");return Math.min(Math.max(e,t),r)},if:(e,t,r)=>e?t:r,typeof:e=>typeof e,length:e=>{if("string"==typeof e||Array.isArray(e))return e.length;throw new Error("length() expects string or array")}};function c(e){let t=0;const r=()=>e[t],n=()=>e[t++],o=(e,n)=>{const o=r();return!!o&&(o.type===e&&((void 0===n||o.value===n)&&(t++,!0)))},i=()=>{let e=null;if("Colon"!==r()?.type&&"Comma"!==r()?.type&&"ArrayEnd"!==r()?.type&&(e=h()),o("Colon")){let t=null;return"Comma"!==r()?.type&&"ArrayEnd"!==r()?.type&&(t=h()),{type:"SliceExpression",start:e,end:t}}return e};function a(){let e=function(){const e=n();if(!e)throw new Error("Unexpected end of input");switch(e.type){case"Number":case"BigInt":case"Boolean":case"String":return{type:"Literal",value:e.value};case"ImaginaryLiteral":return{type:"ImaginaryLiteral",value:e.value};case"NumberWithUnit":return{type:"UnitLiteral",value:e.value,unit:e.unit};case"Identifier":case"Function":return{type:"Identifier",name:e.name};case"Parenthesis":if("("===e.value){const e=h();if(!o("Parenthesis",")"))throw new Error("Expected ')'");return e}case"ArrayStart":{const e=[];let r=[];if(!o("ArrayEnd"))for(;;)if(r.push(h()),!o("Comma")){if(!o("Semicolon")){if(o("ArrayEnd")){e.push(r);break}throw new Error(`Expected ',', ';', or ']' at ${t}`)}e.push(r),r=[]}return e.length?1===e.length?{type:"ArrayExpression",elements:e[0]}:{type:"ArrayExpression",elements:e.map(e=>({type:"ArrayExpression",elements:e}))}:{type:"ArrayExpression",elements:[]}}case"BlockStart":{const e=[];if(!o("BlockEnd")){do{const t=n();if("Identifier"!==t.type&&"String"!==t.type)throw new Error("Invalid object key");if(!o("Colon"))throw new Error("Expected ':' after key");const r=h();e.push({key:t.value,value:r})}while(o("Comma"));if(!o("BlockEnd"))throw new Error(`Expected '}' at ${t}`)}return{type:"ObjectExpression",properties:e}}}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}();for(;;){if(o("ArrayStart")){const r=[];if(!o("ArrayEnd")){do{r.push(i())}while(o("Comma"));if(!o("ArrayEnd"))throw new Error(`Expected ']' at ${t}`)}e={type:"IndexExpression",object:e,selectors:r};continue}if(o("Dot")){const t=n();if("Identifier"!==t.type)throw new Error("Expected property after '.'");e={type:"MemberExpression",object:e,property:{type:"Identifier",name:t.value},optional:!1};continue}if(o("Operator","?.")){e={type:"MemberExpression",object:e,property:{type:"Identifier",name:n().value},optional:!0};continue}break}return e}function s(){if(o("UnaryOperator")){return{type:"UnaryExpression",operator:e[t-1].value,argument:s()}}return function(){let e=a();for(;"Parenthesis"===r()?.type&&"("===r()?.value;){n();const i=[];if("Parenthesis"!==r()?.type||")"!==r()?.value)do{i.push(h())}while(o("Comma"));if(!o("Parenthesis",")"))throw new Error(`Expected ')' at ${t}`);e={type:"CallExpression",callee:e,arguments:i}}return e}()}function l(){let e=s();if(o("Operator","^")){return{type:"BinaryExpression",operator:"^",left:e,right:l()}}return e}function u(){let r=l();for(;o("Operator","*")||o("Operator","/")||o("Operator","%");){r={type:"BinaryExpression",operator:e[t-1].value,left:r,right:l()}}return r}function m(){let i=function(){let r=u();for(;o("Operator","+")||o("Operator","-");)r={type:"BinaryExpression",operator:e[t-1].value,left:r,right:u()};return r}();const a=r();if("Keyword"===a?.type&&["to","in"].includes(a.value)){n();const e=n();if(!e||"Unit"!==e.type)throw new Error(`Expected unit after '${a.value}'`);return{type:"UnitConversion",from:i,to:e.value}}return i}function c(){let r=m();for(;o("Operator",">")||o("Operator","<")||o("Operator",">=")||o("Operator","<=")||o("Operator","==");){r={type:"BinaryExpression",operator:e[t-1].value,left:r,right:m()}}return r}function p(){let r=c();for(;o("Operator","&&")||o("Operator","||");){r={type:"LogicalExpression",operator:e[t-1].value,left:r,right:c()}}return r}function y(){let e=function(){let e=p();for(;o("Operator","??");)e={type:"LogicalExpression",operator:"??",left:e,right:p()};return e}();if(o("Ternary","?")){const t=h();if(!o("Ternary",":"))throw new Error("Expected ':' in ternary");return{type:"ConditionalExpression",test:e,consequent:t,alternate:h()}}return e}function f(){let r=function(){let e=y();for(;o("Operator","|>");)e={type:"PipelineExpression",left:e,right:y()};return e}();if(o("Operator","=")||o("Operator","+=")||o("Operator","-=")||o("Operator","*=")||o("Operator","/=")){const n=e[t-1].value;if("Identifier"!==r.type&&"MemberExpression"!==r.type&&"IndexExpression"!==r.type)throw new Error("Invalid assignment target");return{type:"AssignmentExpression",operator:n,left:r,right:f()}}return r}function h(){return f()}const v=h();if(t<e.length)throw new Error(`Unexpected token at end: ${JSON.stringify(r())}`);return v}const p=e=>e&&"object"==typeof e&&"re"in e&&"im"in e,y=e=>p(e)?(e=>{if(!p(e))return e;const t=e.re,r=Math.abs(e.im),n=e.im<0?"-":"+";return 0===t?1===e.im?"i":-1===e.im?"-i":`${e.im}i`:`${t} ${n} ${1===r?"i":`${r}i`}`})(e):(e=>e&&"object"==typeof e&&"value"in e&&"unit"in e)(e)?`${e.value} ${e.unit}`:(e=>Array.isArray(e)&&e.length>0&&e.every(Array.isArray))(e)?e.map(e=>e.join("\t")).join("\n"):Array.isArray(e)?e.join("\n"):e;return class{constructor(){this.math=n,this.units=function(e={}){let t={...e};function r(e){e=e.toLowerCase();for(const r in t)for(const n in t[r]){const o=t[r][n];if(n.toLowerCase()===e||o.unit?.toLowerCase()===e||o.symbol?.toLowerCase()===e)return{type:r,key:n,data:o}}return null}return{getUnits:()=>t,setUnits:e=>{t={...e}},updateType:(e,r)=>{t[e]={...t[e],...r}},addUnit:(e,r,n)=>{t[e]||(t[e]={}),t[e][r]=n},compute(e,t,r){const n=e=>e&&"object"==typeof e&&"value"in e&&"unit"in e,o=(t,r)=>{switch(e){case"+":return t+r;case"-":return t-r;case"*":return t*r;case"/":return t/r;case"%":return t%r;case"^":return Math.pow(t,r)}};if(n(t)&&n(r)){const e=this.findUnit(r.unit),n=this.findUnit(t.unit);if(e.type!==n.type)throw new Error("Cannot operate on different unit types");const i=r.value*(e.data.value/n.data.value);return{value:o(t.value,i),unit:t.unit}}if(n(t)&&!n(r))return{value:o(t.value,r),unit:t.unit};if(!n(t)&&n(r)){return{value:o(t,r.value),unit:r.unit}}return o(t,r)},convert:function(e,n,o){const i=r(n),a=r(o);if(!i)throw new Error(`Unknown unit: ${n}`);if(!a)throw new Error(`Unknown unit: ${o}`);if(i.type!==a.type)throw new Error(`Cannot convert ${n} to ${o} (${a.data.unit||a.key}). ${i.data.unit||i.key} conversion units like ${Object.keys(t[i.type]).join(", ")}`);return{value:e*(i.data.value/a.data.value),unit:a.key}},getAllUnitsFlat:function(){const e=new Set;for(const r in t)for(const n in t[r]){const o=t[r][n],i=n.toLowerCase();if(e.add(i),o.unit){const t=o.unit.toLowerCase();t!==i&&1===t.split(/\s+/).length&&e.add(t)}if(o.symbol){const t=o.symbol.toLowerCase();o.unit&&t===o.unit.toLowerCase()||e.add(t)}}return Array.from(e)},findUnit:r}}(o),this.functions=function(e={}){const t=Object.create(null);for(const r in e)"function"==typeof e[r]&&(t[r]=e[r]);return{getAllFunctionsName:()=>Object.keys(t),register(e,r){if("string"!=typeof e||!e)throw new Error("Formula name must be a non-empty string");if("function"!=typeof r)throw new Error(`Formula "${e}" must be callable`);t[e]=r},get:e=>t[e],has:e=>Object.prototype.hasOwnProperty.call(t,e),remove(e){delete t[e]},all:()=>({...t}),clear(){for(const e in t)delete t[e]},extend(e={}){for(const r in e)"function"==typeof e[r]&&(t[r]=e[r])},clone:()=>createFormulaRegistry(t)}}(m),this.variables=a(),this._cache=new Map}setVariable(e,t){this.variables.set(e,t)}getVariable(e){return this.variables.get(e)}addFunction(e,t){this.functions.register(e,t)}_createContext(){return t({functions:this.functions,variables:this.variables,units:this.units,evaluate:this.evaluate.bind(this)})}tokenize(e){if("string"!=typeof e)throw new Error("Expression must be a string");return function(e,t={}){const r=[];let n="",o="";const i=["+","-","*","/","%","^","=",">","<","!","&","|"],a=["==",">=","<=","&&","||","+=","-=","*=","/=","%=","?.","??","|>"],s=["to","in"],l=t.units?.getAllUnitsFlat?.()||[],u=e=>!e||"Operator"===e.type||"UnaryOperator"===e.type||"Parenthesis"===e.type&&")"!==e.value||"ArrayStart"===e.type||"Semicolon"===e.type||"Comma"===e.type||"Ternary"===e.type,m=(t,o)=>{if(!n)return;if(/^(true|false)$/i.test(n))return r.push({type:"Boolean",value:"true"===n.toLowerCase()}),void(n="");if(s.includes(n))return r.push({type:"Keyword",value:n,pos:o}),void(n="");if(/^\d+n$/.test(n))return r.push({type:"BigInt",value:BigInt(n.slice(0,-1)),pos:o}),void(n="");if(/^0x[0-9a-fA-F]+$/.test(n))return r.push({type:"Number",value:parseInt(n,16),pos:o}),void(n="");if(/^0b[01]+$/.test(n))return r.push({type:"Number",value:parseInt(n,2),pos:o}),void(n="");if(/^[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?$/i.test(n))return r.push({type:"Number",value:parseFloat(n),pos:o}),void(n="");if(/^[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?i$/i.test(n))return r.push({type:"ImaginaryLiteral",value:parseFloat(n.slice(0,-1)),pos:o}),void(n="");if(/^[+-]?i$/i.test(n)){const e="-"===n[0]?-1:1;return r.push({type:"ImaginaryLiteral",value:e,pos:o}),void(n="")}const i=n.match(/^([+-]?\d+(\.\d+)?)([a-zA-Z]+)$/);if(i){const e=parseFloat(i[1]),t=i[3];return r.push({type:l.includes(t)?"NumberWithUnit":"UnknownUnit",value:e,unit:t,pos:o}),void(n="")}if(l.includes(n)){const{prevWord:i}=function(e,t){const r=e.match(/[a-z0-9]+/gi)||[],n=e[t]||null,o=t>0?e[t-1]:null;let i=t;for(;i>0&&/[a-z0-9]/i.test(e[i-1]);)i--;let a=t;for(;a<e.length&&/[a-z0-9]/i.test(e[a]);)a++;const s=e.substring(i,a),l=r.indexOf(s);return{prevWord:l>0?r[l-1]:null,prevChar:o,currentWord:s,currentChar:n,nextWord:-1!==l&&l<r.length-1?r[l+1]:null}}(e,o);if("("!==t&&i&&(!isNaN(parseFloat(i))||"to"===i||"in"===i))return r.push({type:"Unit",value:n,pos:o}),void(n="")}if(/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(n))return"("===t?r.push({type:"Function",name:n,pos:o}):r.push({type:"Identifier",name:n,pos:o}),void(n="");throw new Error(`Invalid token "${n}" at index ${o}`)};for(let t=0;t<e.length;t++){let s=e[t],l=e[t+1];if("/"===s&&"/"===l){for(;t<e.length&&"\n"!==e[t];)t++;continue}if("/"===s&&"*"===l){for(t+=2;t<e.length&&("*"!==e[t]||"/"!==e[t+1]);)t++;t++;continue}if("\"'".includes(s)){o?o===s?(n+=s,r.push({type:"String",value:n.slice(1,-1),pos:t}),n="",o=""):n+=s:(o=s,n+=s);continue}if(o){n+="\\"===s?s+e[++t]:s;continue}const c=s+l;if(a.includes(c))m(s,t),r.push({type:"Operator",value:c,pos:t}),t++;else if("?"!==s){if(":"===s){m(s,t);const e=r[r.length-1];e&&"Ternary"===e.type?r.push({type:"Ternary",value:":"}):r.push({type:"Colon"});continue}if("."===s&&/\d/.test(n)&&/\d/.test(l))n+=s;else if("."!==s){if(i.includes(s)){m(s,t);const e=r[r.length-1];"-"!==s&&"!"!==s||!u(e)?r.push({type:"Operator",value:s,pos:t}):r.push({type:"UnaryOperator",value:s,pos:t});continue}"()".includes(s)?(m(s,t),r.push({type:"Parenthesis",value:s,pos:t})):"["!==s?"]"!==s?"{"!==s?"}"!==s?","!==s?";"!==s?" "!==s?(n+=s,t===e.length-1&&m(null,t)):m(l,t):(m(s,t),r.push({type:"Semicolon",pos:t})):(m(s,t),r.push({type:"Comma",pos:t})):(m(s,t),r.push({type:"BlockEnd",pos:t})):(m(s,t),r.push({type:"BlockStart",pos:t})):(m(s,t),r.push({type:"ArrayEnd",pos:t})):(m(s,t),r.push({type:"ArrayStart",pos:t}))}else m(s,t),r.push({type:"Dot",pos:t})}else r.push({type:"Ternary",value:"?"})}if(o)throw new Error("Unclosed string literal");const c=[];for(let e=0;e<r.length;e++){const t=r[e],n=r[e+1];"Number"!==t?.type||"Unit"!==n?.type?c.push(t):(c.push({type:"NumberWithUnit",value:t.value,unit:n.value,pos:t.pos}),e++)}const p=[];for(let e=0;e<c.length;e++){const t=c[e],r=c[e+1];p.push(t),t&&r&&(["Number","Identifier"].includes(t.type)||"Parenthesis"===t.type&&")"===t.value||"ArrayEnd"===t.type)&&(["Identifier","Function"].includes(r.type)||"Parenthesis"===r.type&&"("===r.value)&&p.push({type:"Operator",value:"*",implicit:!0})}return p}(e,this._createContext())}parse(e){const t=this.tokenize(e);return{tokens:t,ast:c(t)}}evaluate(t){const{ast:r}=this.parse(t);return y(e(r,this._createContext()))}compile(t){if(this._cache.has(t))return this._cache.get(t);const{ast:r}=this.parse(t),n=(t={})=>{const n=this._createContext().withScope(t);return y(e(r,n))};return this._cache.set(t,n),n}clearCache(){this._cache.clear()}}});
|
|
1
|
+
/*! exprify v1.0.3 | * (c) 2026 Nirmal Paul and contributors | GPL-3.0 License*/
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Exprify=t()}(this,function(){"use strict";const e=e=>e&&"object"==typeof e&&"DenseMatrix"===e.exprify&&"data"in e&&"size"in e,t=e=>Array.isArray(e)?e.map(t):e,r=e=>{if(Array.isArray(e)&&e.every(Array.isArray))return[e.length,e[0]?.length||0];if(Array.isArray(e))return[e.length];throw new Error("Matrix data must be an array")},n=e=>({exprify:"DenseMatrix",data:t(e),size:r(e)}),o=r=>e(r)?t(r.data):r,i=t=>e(t)?JSON.stringify(t):Array.isArray(t)||t&&"object"==typeof t?JSON.stringify(t,(t,r)=>(e(r),r)):t;function a(e,t={}){const r=t.variables,i=t.functions,s=t.units,l=e=>e&&"object"==typeof e&&"value"in e&&"unit"in e,u=e=>e&&"object"==typeof e&&"re"in e&&"im"in e,c=e=>Array.isArray(e)&&e.length>0&&e.every(Array.isArray),p=e=>{if(e=o(e),c(e))return e.map(e=>[...e]);if(Array.isArray(e))return[e];throw new Error("Expected matrix-compatible value")},m=e=>{if("number"!=typeof e||!Number.isInteger(e)||e<1)throw new Error("Matrix indices must be positive integers");return e-1},f=(e,r)=>{if((n=e)&&"object"==typeof n&&"SliceExpression"===n.type){const n=null==e.start?1:a(e.start,t),o=null==e.end?r:a(e.end,t),i=m(n),s=m(o);if(s<i)return[];const l=[];for(let e=i;e<=s;e++)l.push(e);return l}var n;return[m(a(e,t))]},y=e=>{if(u(e))return e;if("number"==typeof e)return{re:e,im:0};throw new Error("Complex arithmetic only supports numbers")},h=e=>0===e.im?e.re:e;switch(e.type){case"Literal":return e.value;case"ImaginaryLiteral":return{re:0,im:e.value};case"UnitLiteral":return{value:e.value,unit:e.unit};case"Identifier":return r.get(e.name);case"AssignmentExpression":{const i=a(e.right,t);if("Identifier"===e.left.type)return r.set(e.left.name,i),"ArrayExpression"===e.right.type?n(o(i)):i;if("IndexExpression"===e.left.type&&"Identifier"===e.left.object.type){const t=((e,t,r)=>{const n=c(e)?e.map(e=>[...e]):Array.isArray(e)?[e.slice()]:[],o=t[0],i=t[1];if(!o)throw new Error("Matrix assignment requires at least one index");const a=Math.max(n.length,1),s=f(o,a);if(1===t.length){const e=c(r)?r:p(r);if(e.length!==s.length)throw new Error("Assigned row count does not match slice");return s.forEach((t,r)=>{n[t]=[...e[r]]}),{updatedMatrix:n,selectionResult:1===s.length?[n[s[0]]]:s.map(e=>[n[e]])}}const l=Math.max(...n.map(e=>e.length),0,1),u=f(i,l),m=p(r);if(m.length!==s.length)throw new Error("Assigned row count does not match matrix slice");return m.forEach((e,t)=>{if(e.length!==u.length)throw new Error("Assigned column count does not match matrix slice")}),s.forEach((e,t)=>{n[e]||(n[e]=[]),u.forEach((r,o)=>{n[e][r]=m[t][o]})}),{updatedMatrix:n,selectionResult:1===s.length?[u.map(e=>n[s[0]][e])]:s.map(e=>u.map(t=>n[e][t]))}})(r.get(e.left.object.name),e.left.selectors,i);return r.set(e.left.object.name,t.updatedMatrix),t.selectionResult}throw new Error("Invalid assignment target")}case"FunctionAssignmentExpression":{if("="!==e.operator)throw new Error(`Operator ${e.operator} is not supported for function definitions`);const r=(...r)=>{const n=t.withScope(((e,t)=>{const r={};return e.forEach((e,n)=>{r[e]=t[n]}),r})(e.params,r));return a(e.right,n)};return i.register(e.left.name,r),r}case"UnaryExpression":{const r=a(e.argument,t);switch(e.operator){case"-":return u(r)?h({re:-r.re,im:-r.im}):-r;case"!":return!r}throw new Error(`Unknown unary operator ${e.operator}`)}case"BinaryExpression":{let r=a(e.left,t),n=a(e.right,t);if(l(r)||l(n)){if(!s)throw new Error("Unit system not available");return s.compute(e.operator,r,n)}if("*"===e.operator&&(Array.isArray(r)||Array.isArray(n)))return((e,t)=>{const r=p(e),n=p(t);if(r[0].length!==n.length)throw new Error("Matrix dimensions do not allow multiplication");return r.map(e=>n[0].map((t,r)=>e.reduce((e,t,o)=>e+t*n[o][r],0)))})(r,n);if(u(r)||u(n))return((e,t,r)=>{const n=y(t),o=y(r);switch(e){case"+":return h({re:n.re+o.re,im:n.im+o.im});case"-":return h({re:n.re-o.re,im:n.im-o.im});case"*":return h({re:n.re*o.re-n.im*o.im,im:n.re*o.im+n.im*o.re});case"/":{const e=o.re**2+o.im**2;if(0===e)throw new Error("Division by zero");return h({re:(n.re*o.re+n.im*o.im)/e,im:(n.im*o.re-n.re*o.im)/e})}default:throw new Error(`Operator ${e} is not supported for complex numbers`)}})(e.operator,r,n);switch(e.operator){case"+":return r+n;case"-":return r-n;case"*":return r*n;case"/":return r/n;case"%":return r%n;case"^":return r**n;case">":return r>n;case"<":return r<n;case">=":return r>=n;case"<=":return r<=n;case"==":return r===n}throw new Error(`Unknown operator ${e.operator}`)}case"LogicalExpression":{const r=a(e.left,t);if("&&"===e.operator)return r&&a(e.right,t);if("||"===e.operator)return r||a(e.right,t);if("??"===e.operator)return r??a(e.right,t);throw new Error(`Unknown logical operator ${e.operator}`)}case"CallExpression":{const r=e.callee.name;return i.get(r)(...e.arguments.map(e=>a(e,t)))}case"PipelineExpression":{const r=a(e.left,t);if("CallExpression"===e.right.type){const n=e.right.callee.name;return i.get(n)(...[r,...e.right.arguments.map(e=>a(e,t))])}if("Identifier"===e.right.type){return i.get(e.right.name)(r)}throw new Error("Invalid pipeline target")}case"UnitConversion":{const r=a(e.from,t);if(!l(r))throw new Error("Left side must be a unit value");if(!s)throw new Error("Unit system not available");return s.convert(r.value,r.unit,e.to)}case"ArrayExpression":return e.elements.map(e=>a(e,t));case"IndexExpression":return((e,t)=>{const r=p(e);if(1===t.length){const e=f(t[0],r.length).map(e=>{if(e>=r.length)throw new Error("Row index out of range");return[...r[e]]});return 1===e.length?e[0]:e}const n=f(t[0],r.length),o=f(t[1],r[0]?.length||0),i=n.map(e=>{if(e>=r.length)throw new Error("Row index out of range");return o.map(t=>{if(t>=r[e].length)throw new Error("Column index out of range");return r[e][t]})});return 1===n.length&&1===o.length?i[0][0]:1===n.length?i[0]:1===o.length?i.map(e=>[e[0]]):i})(a(e.object,t),e.selectors);case"ObjectExpression":{const r={};for(let n of e.properties)r[n.key]=a(n.value,t);return r}case"MemberExpression":{const r=a(e.object,t);if(e.optional&&null==r)return;return r[e.property.name]}default:throw new Error(`Unknown AST node type: ${e.type}`)}}function s({variables:e,functions:t,units:r,evaluate:n}){if(!e)throw new Error("Variable store missing");if(!t)throw new Error("Function registry missing");if(!r)throw new Error("Units list missing");if(!n)throw new Error("evaluate function missing");return{variables:e,functions:t,units:r,evaluate:n,withScope(o={}){const i={...e.all?.(),...o};return s({functions:t,evaluate:n,units:r,variables:{get:e=>i[e],set:(e,t)=>i[e]=t,all:()=>i}})}}}const l=(e,t)=>typeof e==typeof t&&("number"==typeof e||"bigint"==typeof e),u=Object.freeze({power:function(e,t){if(l(e,t))return e**t;throw new Error("Invalid types for ^")},multiply:function(e,t){if(l(e,t))return e*t;throw new Error("Invalid types for *")},divide:function(e,t){if(l(e,t)){if(0===t)throw new Error("Division by zero");return e/t}throw new Error("Invalid types for /")},add:function(e,t){if(l(e,t))return e+t;if("string"==typeof e&&"string"==typeof t)return e+t;throw new Error("Invalid types for +")},subtract:function(e,t){if(l(e,t))return e-t;throw new Error("Invalid types for -")},modulus:function(e,t){if(l(e,t))return e%t;throw new Error("Invalid types for %")}});const c={length:{m:{value:1,unit:"meter",symbol:"m"},cm:{value:.01,unit:"centimeter",symbol:"cm"},mm:{value:.001,unit:"millimeter",symbol:"mm"},km:{value:1e3,unit:"kilometer",symbol:"km"},um:{value:1e-6,unit:"micrometer",symbol:"um",note:"also called micron"},nm:{value:1e-9,unit:"nanometer",symbol:"nm"},px:{value:264583e-9,unit:"pixel",symbol:"px",note:"96dpi standard"},em:{value:.004233328,unit:"em",symbol:"em",note:"1em = 16px by default"},rem:{value:.004233328,unit:"rem",symbol:"rem",note:"root em = 16px by default"},pt:{value:352778e-9,unit:"point",symbol:"pt",note:"1pt = 1/72 inch"},pc:{value:.00423333,unit:"pica",symbol:"pc",note:"1pc = 12pt"},inch:{value:.0254,unit:"inch",symbol:"in"},ft:{value:.3048,unit:"foot",symbol:"ft"},yd:{value:.9144,unit:"yard",symbol:"yd"},mi:{value:1609.344,unit:"mile",symbol:"mi"},thou:{value:254e-7,unit:"mil",symbol:"thou",note:"thousandth of an inch"},furlong:{value:201.168,unit:"furlong",symbol:"fur",note:"220 yards"},nmi:{value:1852,unit:"nautical mile",symbol:"nmi"},fathom:{value:1.8288,unit:"fathom",symbol:"fathom"},au:{value:1496e8,unit:"astronomical unit",symbol:"AU"},ly:{value:94607e11,unit:"light year",symbol:"ly"},pc:{value:30857e12,unit:"parsec",symbol:"pc"}},weight:{mg:{value:1e-6,unit:"milligram",symbol:"mg"},g:{value:.001,unit:"gram",symbol:"g"},kg:{value:1,unit:"kilogram",symbol:"kg"},t:{value:1e3,unit:"tonne",symbol:"t",note:"metric ton"},lb:{value:.453592,unit:"pound",symbol:"lb"},oz:{value:.0283495,unit:"ounce",symbol:"oz"},stone:{value:6.35029,unit:"stone",symbol:"st",note:"1 stone = 14 lb"}},time:{s:{value:1,unit:"second",symbol:"s"},min:{value:60,unit:"minute",symbol:"min"},h:{value:3600,unit:"hour",symbol:"h"},day:{value:86400,unit:"day",symbol:"d"},week:{value:604800,unit:"week",symbol:"wk"},month:{value:2629800,unit:"month",symbol:"mo",note:"average month = 30.44 days"},year:{value:31557600,unit:"year",symbol:"yr",note:"average year = 365.25 days"}},voltage:{V:{value:1,unit:"volt",symbol:"V"},mV:{value:.001,unit:"millivolt",symbol:"mV"},kV:{value:1e3,unit:"kilovolt",symbol:"kV"},MV:{value:1e6,unit:"megavolt",symbol:"MV"},GV:{value:1e9,unit:"gigavolt",symbol:"GV"},statV:{value:299.792458,unit:"statvolt",symbol:"statV",note:"CGS unit"},abV:{value:1e-8,unit:"abvolt",symbol:"abV",note:"CGS electromagnetic unit"}},frequency:{Hz:{value:1,unit:"hertz",symbol:"Hz",note:"1 cycle per second"},kHz:{value:1e3,unit:"kilohertz",symbol:"kHz"},MHz:{value:1e6,unit:"megahertz",symbol:"MHz"},GHz:{value:1e9,unit:"gigahertz",symbol:"GHz"},THz:{value:1e12,unit:"terahertz",symbol:"THz"}},power:{W:{value:1,unit:"watt",symbol:"W",note:"1 joule per second"},mW:{value:.001,unit:"milliwatt",symbol:"mW"},kW:{value:1e3,unit:"kilowatt",symbol:"kW"},MW:{value:1e6,unit:"megawatt",symbol:"MW"},GW:{value:1e9,unit:"gigawatt",symbol:"GW"},HP:{value:745.7,unit:"horsepower",symbol:"HP",note:"mechanical HP = 745.7 W"},kcal_per_h:{value:1.163,unit:"kilocalorie per hour",symbol:"kcal/h",note:"= 1.163 W"},BTU_per_h:{value:.29307107,unit:"BTU per hour",symbol:"BTU/h",note:"= 0.293 W"}},sound:{dB:{value:1,unit:"decibel",symbol:"dB",note:"logarithmic unit of sound intensity"},dBA:{value:1,unit:"A-weighted decibel",symbol:"dBA",note:"Adjusted for human hearing"},dBC:{value:1,unit:"C-weighted decibel",symbol:"dBC",note:"Flat weighting for high-level sounds"}},temperature:{K:{value:1,unit:"kelvin",symbol:"K"},C:{value:1,unit:"Celsius",symbol:"°C",note:"°C → K: add 273.15"},F:{value:1,unit:"Fahrenheit",symbol:"°F",note:"°F → K: (°F - 32) * 5/9 + 273.15"}},pressure:{Pa:{value:1,unit:"pascal",symbol:"Pa"},kPa:{value:1e3,unit:"kilopascal",symbol:"kPa"},MPa:{value:1e6,unit:"megapascal",symbol:"MPa"},bar:{value:1e5,unit:"bar",symbol:"bar"},atm:{value:101325,unit:"atmosphere",symbol:"atm"},psi:{value:6894.757,unit:"pound per square inch",symbol:"psi"},mmHg:{value:133.322,unit:"millimeter of mercury",symbol:"mmHg"}},energy:{J:{value:1,unit:"joule",symbol:"J"},kJ:{value:1e3,unit:"kilojoule",symbol:"kJ"},cal:{value:4.184,unit:"calorie",symbol:"cal"},kcal:{value:4184,unit:"kilocalorie",symbol:"kcal"},eV:{value:160218e-24,unit:"electronvolt",symbol:"eV"},BTU:{value:1055.06,unit:"BTU",symbol:"BTU"}},force:{N:{value:1,unit:"newton",symbol:"N"},kN:{value:1e3,unit:"kilonewton",symbol:"kN"},lbf:{value:4.44822,unit:"pound-force",symbol:"lbf"},kgf:{value:9.80665,unit:"kilogram-force",symbol:"kgf"},dyne:{value:1e-5,unit:"dyne",symbol:"dyn"}},area:{m2:{value:1,unit:"square meter",symbol:"m²"},cm2:{value:1e-4,unit:"square centimeter",symbol:"cm²"},km2:{value:1e6,unit:"square kilometer",symbol:"km²"},acre:{value:4046.856,unit:"acre",symbol:"acre"},hectare:{value:1e4,unit:"hectare",symbol:"ha"},ft2:{value:.092903,unit:"square foot",symbol:"ft²"},yd2:{value:.836127,unit:"square yard",symbol:"yd²"}},volume:{m3:{value:1,unit:"cubic meter",symbol:"m³"},L:{value:.001,unit:"liter",symbol:"L"},mL:{value:1e-6,unit:"milliliter",symbol:"mL"},gallon:{value:.00378541,unit:"US gallon",symbol:"gal"},pint:{value:473176e-9,unit:"US pint",symbol:"pt"},floz:{value:29574e-9,unit:"US fluid ounce",symbol:"fl oz"}},current:{A:{value:1,unit:"ampere",symbol:"A"},mA:{value:.001,unit:"milliampere",symbol:"mA"},uA:{value:1e-6,unit:"microampere",symbol:"uA"},kA:{value:1e3,unit:"kiloampere",symbol:"kA"}},resistance:{ohm:{value:1,unit:"ohm"},kohm:{value:1e3,unit:"kiloohm"},megaohm:{value:1e6,unit:"megaohm"},S:{value:1,unit:"siemens",symbol:"S",note:"conductance"}},capacitance:{F:{value:1,unit:"farad",symbol:"F"},mF:{value:.001,unit:"millifarad"},uF:{value:1e-6,unit:"microfarad"}},inductance:{H:{value:1,unit:"henry",symbol:"H"},mH:{value:.001,unit:"millihenry",symbol:"mH"},uH:{value:1e-6,unit:"microhenry",symbol:"uH"}},light:{cd:{value:1,unit:"candela",symbol:"cd"},lm:{value:1,unit:"lumen",symbol:"lm"},lx:{value:1,unit:"lux",symbol:"lx"}},data:{bit:{value:1,unit:"bit",symbol:"bit"},B:{value:8,unit:"byte",symbol:"B"},KB:{value:8e3,unit:"kilobyte",symbol:"KB"},MB:{value:8e6,unit:"megabyte",symbol:"MB"},GB:{value:8e9,unit:"gigabyte",symbol:"GB"},TB:{value:8e12,unit:"terabyte",symbol:"TB"}},angle:{deg:{value:1,unit:"degree",symbol:"°"},rad:{value:57.2958,unit:"radian",symbol:"rad",note:"1 rad = 57.2958°"},grad:{value:.9,unit:"grad",symbol:"grad",note:"1 grad = 0.9°"}},radiation:{Gy:{value:1,unit:"gray",symbol:"Gy",note:"Absorbed dose: 1 Gy = 1 J/kg"},mGy:{value:.001,unit:"milligray",symbol:"mGy"},rad:{value:.01,unit:"rad",symbol:"rad",note:"1 rad = 0.01 Gy"},Sv:{value:1,unit:"sievert",symbol:"Sv",note:"Biological effect dose equivalent"},mSv:{value:.001,unit:"millisievert",symbol:"mSv"},rem:{value:.01,unit:"rem",symbol:"rem",note:"1 rem = 0.01 Sv"},Bq:{value:1,unit:"becquerel",symbol:"Bq",note:"1 decay per second"},kBq:{value:1e3,unit:"kilobecquerel",symbol:"kBq"},MBq:{value:1e6,unit:"megabecquerel",symbol:"MBq"},GBq:{value:1e9,unit:"gigabecquerel",symbol:"GBq"},Ci:{value:37e9,unit:"curie",symbol:"Ci",note:"1 Ci = 3.7 x 10¹⁰ decays per second"},mCi:{value:37e6,unit:"millicurie",symbol:"mCi"}}},p=/^[a-zA-Z_$][a-zA-Z0-9_$]*$/;function m(e={}){let t=Object.create(null);for(const r in e)t[r]=e[r];return{set(e,r,{override:n=!0}={}){if("string"!=typeof e||!e)throw new Error("Variable name must be a non-empty string");if(!p.test(e))throw new Error(`Variable Name Error: '${e}' is not a valid variable name`);if(void 0===r)throw new Error(`Variable Value Error: '${e}' cannot be undefined`);if(!n&&e in variablesDB)throw new Error(`Variable '${e}' already exists`);t[e]=r},get:e=>t[e],has:e=>Object.prototype.hasOwnProperty.call(t,e),remove(e){delete t[e]},all:()=>({...t}),clear(){t=Object.create(null)},merge(e={}){for(const r in e)t[r]=e[r]},clone:()=>m(t)}}function f(e){if(e=o(e),!Array.isArray(e)||0===e.length)throw new Error("det() expects a non-empty matrix");if(!e.every(Array.isArray))throw new Error("det() expects a 2D matrix");const t=e.length;if(!e.every(e=>e.length===t))throw new Error("det() expects a square matrix");for(const t of e)for(const e of t)if("number"!=typeof e&&"bigint"!=typeof e)throw new Error("det() matrix values must be numeric")}function y(e){return f(e=o(e)),1===e.length?e[0][0]:2===e.length?e[0][0]*e[1][1]-e[0][1]*e[1][0]:e[0].reduce((t,r,n)=>{const o=e.slice(1).map(e=>e.filter((e,t)=>t!==n));return t+(n%2==0?r:-r)*y(o)},0)}function h(e){const t=o(e);if(!Array.isArray(t))throw new Error("Expected matrix data");return t}function d(e){const t=h(e).map(e=>[...e]);f(t);const r=t.length,o=Array.from({length:r},(e,t)=>t);for(let e=0;e<r;e++){let n=e,i=Math.abs(t[e][e]);for(let o=e+1;o<r;o++){const r=Math.abs(t[o][e]);r>i&&(i=r,n=o)}if(0===i)throw new Error("Matrix is singular");n!==e&&([t[e],t[n]]=[t[n],t[e]],[o[e],o[n]]=[o[n],o[e]]);for(let n=e+1;n<r;n++){t[n][e]/=t[e][e];for(let o=e+1;o<r;o++)t[n][o]-=t[n][e]*t[e][o]}}const i=t.map((e,t)=>e.map((e,r)=>t===r?1:t>r?e:0)),a=t.map((e,t)=>e.map((e,r)=>t<=r?e:0));return{L:n(i),U:n(a),p:o}}function v(e,t){const r=h(e).map(e=>[...e]),o=h(t).map(e=>[...e]);f(r),f(o);const i=r.length;if(o.length!==i)throw new Error("A and Q must have the same dimensions");const a=[],s=[];for(let e=0;e<i;e++)for(let t=0;t<i;t++){const n=new Array(i*i).fill(0);for(let o=0;o<i;o++)n[o*i+t]+=r[e][o],n[e*i+o]+=r[t][o];a.push(n),s.push(-o[e][t])}const l=function(e,t){const r=e.length,n=e.map((e,r)=>[...e,t[r]]);for(let e=0;e<r;e++){let t=e,o=Math.abs(n[e][e]);for(let i=e+1;i<r;i++){const r=Math.abs(n[i][e]);r>o&&(o=r,t=i)}if(0===o)throw new Error("Linear system is singular");t!==e&&([n[e],n[t]]=[n[t],n[e]]);const i=n[e][e];for(let t=e;t<=r;t++)n[e][t]/=i;for(let t=0;t<r;t++){if(t===e)continue;const o=n[t][e];for(let i=e;i<=r;i++)n[t][i]-=o*n[e][i]}}return n.map(e=>e[r])}(a,s),u=[];for(let e=0;e<i;e++)u.push(l.slice(e*i,(e+1)*i));return n(u)}function g(e,t){return e.reduce((e,r,n)=>e+r*t**n,0)}function b(e,t){const r=[...e].reverse(),n=[r[0]];for(let e=1;e<r.length-1;e++)n.push(r[e]+n[e-1]*t);const o=r[r.length-1]+n[n.length-1]*t;return{quotient:n.reverse(),remainder:o}}function w(e){const[t,r,n]=e,o=r**2-4*n*t;if(o<0)throw new Error("Only real roots are supported");const i=Math.sqrt(o);return[(-r+i)/(2*n),(-r-i)/(2*n)]}function E(e,t){return e.reduce((e,r,n)=>e+r*t[n],0)}function x(e){return Math.sqrt(E(e,e))}function A(e,t){return e.map(e=>e*t)}function k(e,t){return e.map((e,r)=>e-t[r])}function $(e,t){const r=function(e){const t=e.replace(/\s+/g,"");return t?t.replace(/-/g,"+-").split("+").filter(Boolean):[]}(e),n=new Map;for(const e of r)if(e.includes(t)){const[r,o]=e.split(t);let i;if(""===r||"+"===r)i=1;else if("-"===r)i=-1;else{const e=r.endsWith("*")?r.slice(0,-1):r;i=Number(e)}if(!Number.isFinite(i))throw new Error("Unsupported algebra term");let a=1;if(o){if(!o.startsWith("^"))throw new Error("Unsupported algebra term");a=Number(o.slice(1))}if(!Number.isInteger(a)||a<0)throw new Error("Only non-negative integer powers are supported");n.set(a,(n.get(a)||0)+i)}else{const t=Number(e);if(!Number.isFinite(t))throw new Error("Unsupported algebra term");n.set(0,(n.get(0)||0)+t)}return n}function M(e,t){const r=[...e.entries()].filter(([,e])=>0!==e).sort((e,t)=>t[0]-e[0]);return r.length?r.map(([e,r],n)=>{const o=r<0,i=Math.abs(r);let a;return a=0===e?`${i}`:1===e?1===i?t:`${i} * ${t}`:1===i?`${t}^${e}`:`${i} * ${t}^${e}`,0===n?o?`-${a}`:a:o?`- ${a}`:`+ ${a}`}).join(" "):"0"}const O={max:(...e)=>{if(!e.length)throw new Error("max() requires arguments");return Math.max(...e)},min:(...e)=>{if(!e.length)throw new Error("min() requires arguments");return Math.min(...e)},abs:e=>Math.abs(e),round:e=>Math.round(e),floor:e=>Math.floor(e),ceil:e=>Math.ceil(e),sqrt:e=>{if(e<0)throw new Error("sqrt() domain error");return Math.sqrt(e)},pow:(e,t)=>e**t,det:e=>y(e),polynomialRoot:(...e)=>function(...e){for(;e.length>1&&0===e[e.length-1];)e.pop();const t=e.length-1;if(t<1)throw new Error("polynomialRoot() expects at least a linear polynomial");if(1===t){const[t,r]=e;return[-t/r]}if(2===t)return w(e);if(3===t){const t=e[0];e[3];const r=[],n=Math.abs(t);for(let e=1;e<=Math.max(1,n);e++)n%e===0&&r.push(e,-e);for(const t of r)if(0===g(e,t))return[t,...w(b(e,t).quotient)]}throw new Error("polynomialRoot() currently supports degree up to 3")}(...e),lsolve:(e,t)=>function(e,t){const{L:r,U:o,p:i}=d(e),a=h(e),s=h(t),l=Array.isArray(s[0])?s.map(e=>e[0]):s;if(a.length!==l.length)throw new Error("Right-hand side dimension mismatch");const u=i.map(e=>l[e]),c=new Array(a.length).fill(0);for(let e=0;e<a.length;e++){c[e]=u[e];for(let t=0;t<e;t++)c[e]-=r.data[e][t]*c[t]}const p=new Array(a.length).fill(0);for(let e=a.length-1;e>=0;e--){p[e]=c[e];for(let t=e+1;t<a.length;t++)p[e]-=o.data[e][t]*p[t];p[e]/=o.data[e][e]}return n(p.map(e=>[e]))}(e,t),lup:e=>d(e),lyap:(e,t)=>v(e,t),qr:e=>function(e){const t=h(e).map(e=>[...e]);if(!t.length||!t.every(e=>e.length===t[0].length))throw new Error("qr() expects a rectangular matrix");const r=t.length,o=t[0].length,i=(a=t)[0].map((e,t)=>a.map(e=>e[t]));var a;const s=[];for(let e=0;e<o;e++){let t=[...i[e]];for(let r=0;r<s.length;r++){const n=E(s[r],i[e]);t=k(t,A(s[r],n))}const r=x(t);if(0===r)throw new Error("qr() requires linearly independent columns");s.push(A(t,1/r))}for(let e=0;s.length<r&&e<r;e++){let t=Array.from({length:r},(t,r)=>r===e?1:0);for(const e of s)t=k(t,A(e,E(e,t)));const n=x(t);n>1e-10&&s.push(A(t,1/n))}const l=Array.from({length:r},(e,t)=>s.map(e=>e[t])),u=Array.from({length:r},()=>Array(o).fill(0));for(let e=0;e<r;e++)for(let t=0;t<o;t++)u[e][t]=E(s[e],i[t]);return{Q:n(l),R:n(u)}}(e),simplify:e=>{if("string"!=typeof e)throw new Error("simplify() expects an expression string");return function(e){const t=e.replace(/\s+/g,"").match(/[a-zA-Z]+/),r=t?.[0]||"x";return M($(e,r),r)}(e)},derivative:(e,t="x")=>{if("string"!=typeof e||"string"!=typeof t)throw new Error("derivative() expects expression and variable strings");return function(e,t){const r=$(e,t),n=new Map;for(const[e,t]of r.entries())0!==e&&n.set(e-1,(n.get(e-1)||0)+t*e);return M(n,t)}(e,t)},sin:e=>Math.sin(e),cos:e=>Math.cos(e),tan:e=>Math.tan(e),asin:e=>Math.asin(e),acos:e=>Math.acos(e),atan:e=>Math.atan(e),log:e=>{if(e<=0)throw new Error("log() domain error");return Math.log(e)},log10:e=>{if(e<=0)throw new Error("log10() domain error");return Math.log10(e)},exp:e=>Math.exp(e),random:()=>Math.random(),and:(e,t)=>Boolean(e&&t),or:(e,t)=>Boolean(e||t),not:e=>!e,"!":e=>!e,eq:(e,t)=>e===t,neq:(e,t)=>e!==t,notEqual:(e,t)=>e!==t,gt:(e,t)=>e>t,greaterThan:(e,t)=>e>t,lt:(e,t)=>e<t,lessThan:(e,t)=>e<t,gte:(e,t)=>e>=t,greaterThanOrEqual:(e,t)=>e>=t,lte:(e,t)=>e<=t,lessThanOrEqual:(e,t)=>e<=t,clamp:(e,t,r)=>{if(t>r)throw new Error("clamp(): min > max");return Math.min(Math.max(e,t),r)},if:(e,t,r)=>e?t:r,typeof:e=>typeof e,length:e=>{if("string"==typeof e||Array.isArray(e))return e.length;throw new Error("length() expects string or array")}};function U(e){let t=0;const r=()=>e[t],n=()=>e[t++],o=(e,n)=>{const o=r();return!!o&&(o.type===e&&((void 0===n||o.value===n)&&(t++,!0)))},i=()=>{let e=null;if("Colon"!==r()?.type&&"Comma"!==r()?.type&&"ArrayEnd"!==r()?.type&&(e=h()),o("Colon")){let t=null;return"Comma"!==r()?.type&&"ArrayEnd"!==r()?.type&&(t=h()),{type:"SliceExpression",start:e,end:t}}return e};function a(){let e=function(){const e=n();if(!e)throw new Error("Unexpected end of input");switch(e.type){case"Number":case"BigInt":case"Boolean":case"String":return{type:"Literal",value:e.value};case"ImaginaryLiteral":return{type:"ImaginaryLiteral",value:e.value};case"NumberWithUnit":return{type:"UnitLiteral",value:e.value,unit:e.unit};case"Identifier":case"Function":return{type:"Identifier",name:e.name};case"Parenthesis":if("("===e.value){const e=h();if(!o("Parenthesis",")"))throw new Error("Expected ')'");return e}case"ArrayStart":{const e=[];let r=[];if(!o("ArrayEnd"))for(;;)if(r.push(h()),!o("Comma")){if(!o("Semicolon")){if(o("ArrayEnd")){e.push(r);break}throw new Error(`Expected ',', ';', or ']' at ${t}`)}e.push(r),r=[]}return e.length?1===e.length?{type:"ArrayExpression",elements:e[0]}:{type:"ArrayExpression",elements:e.map(e=>({type:"ArrayExpression",elements:e}))}:{type:"ArrayExpression",elements:[]}}case"BlockStart":{const e=[];if(!o("BlockEnd")){do{const t=n();if("Identifier"!==t.type&&"String"!==t.type)throw new Error("Invalid object key");if(!o("Colon"))throw new Error("Expected ':' after key");const r=h();e.push({key:t.value,value:r})}while(o("Comma"));if(!o("BlockEnd"))throw new Error(`Expected '}' at ${t}`)}return{type:"ObjectExpression",properties:e}}}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}();for(;;){if(o("ArrayStart")){const r=[];if(!o("ArrayEnd")){do{r.push(i())}while(o("Comma"));if(!o("ArrayEnd"))throw new Error(`Expected ']' at ${t}`)}e={type:"IndexExpression",object:e,selectors:r};continue}if(o("Dot")){const t=n();if("Identifier"!==t.type)throw new Error("Expected property after '.'");e={type:"MemberExpression",object:e,property:{type:"Identifier",name:t.value},optional:!1};continue}if(o("Operator","?.")){e={type:"MemberExpression",object:e,property:{type:"Identifier",name:n().value},optional:!0};continue}break}return e}function s(){if(o("UnaryOperator")){return{type:"UnaryExpression",operator:e[t-1].value,argument:s()}}return function(){let e=a();for(;"Parenthesis"===r()?.type&&"("===r()?.value;){n();const i=[];if("Parenthesis"!==r()?.type||")"!==r()?.value)do{i.push(h())}while(o("Comma"));if(!o("Parenthesis",")"))throw new Error(`Expected ')' at ${t}`);e={type:"CallExpression",callee:e,arguments:i}}return e}()}function l(){let e=s();if(o("Operator","^")){return{type:"BinaryExpression",operator:"^",left:e,right:l()}}return e}function u(){let r=l();for(;o("Operator","*")||o("Operator","/")||o("Operator","%");){r={type:"BinaryExpression",operator:e[t-1].value,left:r,right:l()}}return r}function c(){let i=function(){let r=u();for(;o("Operator","+")||o("Operator","-");)r={type:"BinaryExpression",operator:e[t-1].value,left:r,right:u()};return r}();const a=r();if("Keyword"===a?.type&&["to","in"].includes(a.value)){n();const e=n();if(!e||"Unit"!==e.type)throw new Error(`Expected unit after '${a.value}'`);return{type:"UnitConversion",from:i,to:e.value}}return i}function p(){let r=c();for(;o("Operator",">")||o("Operator","<")||o("Operator",">=")||o("Operator","<=")||o("Operator","==");){r={type:"BinaryExpression",operator:e[t-1].value,left:r,right:c()}}return r}function m(){let r=p();for(;o("Operator","&&")||o("Operator","||");){r={type:"LogicalExpression",operator:e[t-1].value,left:r,right:p()}}return r}function f(){let e=function(){let e=m();for(;o("Operator","??");)e={type:"LogicalExpression",operator:"??",left:e,right:m()};return e}();if(o("Ternary","?")){const t=h();if(!o("Ternary",":"))throw new Error("Expected ':' in ternary");return{type:"ConditionalExpression",test:e,consequent:t,alternate:h()}}return e}function y(){let r=function(){let e=f();for(;o("Operator","|>");)e={type:"PipelineExpression",left:e,right:f()};return e}();if(o("Operator","=")||o("Operator","+=")||o("Operator","-=")||o("Operator","*=")||o("Operator","/=")){const n=e[t-1].value;if("CallExpression"===r.type){if(!("Identifier"===r.callee?.type&&r.arguments.every(e=>"Identifier"===e.type)))throw new Error("Invalid function definition");const e=y();return{type:"FunctionAssignmentExpression",operator:n,left:{type:"Identifier",name:r.callee.name},params:r.arguments.map(e=>e.name),right:e}}if("Identifier"!==r.type&&"MemberExpression"!==r.type&&"IndexExpression"!==r.type)throw new Error("Invalid assignment target");return{type:"AssignmentExpression",operator:n,left:r,right:y()}}return r}function h(){return y()}const d=h();if(t<e.length)throw new Error(`Unexpected token at end: ${JSON.stringify(r())}`);return d}const C=e=>e&&"object"==typeof e&&"re"in e&&"im"in e,B=e=>"number"!=typeof e||Number.isInteger(e)?String(e):Number(e.toFixed(14)).toString(),I=t=>C(t)?(e=>{if(!C(e))return e;const t=e.re,r=Math.abs(e.im),n=e.im<0?"-":"+";return 0===t?1===e.im?"i":-1===e.im?"-i":`${e.im}i`:`${t} ${n} ${1===r?"i":`${r}i`}`})(t):(e=>e&&"object"==typeof e&&"value"in e&&"unit"in e)(t)?`${t.value} ${t.unit}`:e(t)?i(t):(e=>Array.isArray(e)&&e.length>0&&e.every(Array.isArray))(t)?t.map(e=>e.map(B).join("\t")).join("\n"):Array.isArray(t)?JSON.stringify(t):t&&"object"==typeof t?i(t):t;return class{constructor(){this.math=u,this.units=function(e={}){let t={...e};function r(e){e=e.toLowerCase();for(const r in t)for(const n in t[r]){const o=t[r][n];if(n.toLowerCase()===e||o.unit?.toLowerCase()===e||o.symbol?.toLowerCase()===e)return{type:r,key:n,data:o}}return null}return{getUnits:()=>t,setUnits:e=>{t={...e}},updateType:(e,r)=>{t[e]={...t[e],...r}},addUnit:(e,r,n)=>{t[e]||(t[e]={}),t[e][r]=n},compute(e,t,r){const n=e=>e&&"object"==typeof e&&"value"in e&&"unit"in e,o=(t,r)=>{switch(e){case"+":return t+r;case"-":return t-r;case"*":return t*r;case"/":return t/r;case"%":return t%r;case"^":return Math.pow(t,r)}};if(n(t)&&n(r)){const e=this.findUnit(r.unit),n=this.findUnit(t.unit);if(e.type!==n.type)throw new Error("Cannot operate on different unit types");const i=r.value*(e.data.value/n.data.value);return{value:o(t.value,i),unit:t.unit}}if(n(t)&&!n(r))return{value:o(t.value,r),unit:t.unit};if(!n(t)&&n(r)){return{value:o(t,r.value),unit:r.unit}}return o(t,r)},convert:function(e,n,o){const i=r(n),a=r(o);if(!i)throw new Error(`Unknown unit: ${n}`);if(!a)throw new Error(`Unknown unit: ${o}`);if(i.type!==a.type)throw new Error(`Cannot convert ${n} to ${o} (${a.data.unit||a.key}). ${i.data.unit||i.key} conversion units like ${Object.keys(t[i.type]).join(", ")}`);return{value:e*(i.data.value/a.data.value),unit:a.key}},getAllUnitsFlat:function(){const e=new Set;for(const r in t)for(const n in t[r]){const o=t[r][n],i=n.toLowerCase();if(e.add(i),o.unit){const t=o.unit.toLowerCase();t!==i&&1===t.split(/\s+/).length&&e.add(t)}if(o.symbol){const t=o.symbol.toLowerCase();o.unit&&t===o.unit.toLowerCase()||e.add(t)}}return Array.from(e)},findUnit:r}}(c),this.functions=function(e={}){const t=Object.create(null);for(const r in e)"function"==typeof e[r]&&(t[r]=e[r]);return{getAllFunctionsName:()=>Object.keys(t),register(e,r){if("string"!=typeof e||!e)throw new Error("Formula name must be a non-empty string");if("function"!=typeof r)throw new Error(`Formula "${e}" must be callable`);t[e]=r},get:e=>t[e],has:e=>Object.prototype.hasOwnProperty.call(t,e),remove(e){delete t[e]},all:()=>({...t}),clear(){for(const e in t)delete t[e]},extend(e={}){for(const r in e)"function"==typeof e[r]&&(t[r]=e[r])},clone:()=>createFormulaRegistry(t)}}(O),this.variables=m(),this._cache=new Map,this.variables.set("pi",Math.PI),this.variables.set("e",Math.E),this.addFunction("parse",e=>{if("string"!=typeof e)throw new Error("parse() expects an expression string");return e}),this.addFunction("leafCount",e=>{let t=e;if("string"==typeof e)try{t=this.parse(e).ast}catch{return(e=>{const t=e.replace(/(^|[{,]\s*)[a-zA-Z_][a-zA-Z0-9_]*\s*:/g,"$1").match(/\d+(\.\d+)?(e[+-]?\d+)?n?|[a-zA-Z_][a-zA-Z0-9_]*/gi);return t?t.length:0})(e)}const r=e=>{if(!e||"object"!=typeof e)return 0;switch(e.type){case"Literal":case"ImaginaryLiteral":case"UnitLiteral":case"Identifier":return 1;default:return Object.values(e).reduce((e,t)=>Array.isArray(t)?e+t.reduce((e,t)=>e+r(t),0):e+r(t),0)}};return r(t)}),this.addFunction("matrix",e=>n(e)),this.addFunction("sparse",e=>n(e)),this.addFunction("rationalize",(e,t=!1)=>{if("string"!=typeof e)throw new Error("rationalize() expects an expression string");const r=e.replace(/\s+/g,"").replace(/(\d)([a-zA-Z(])/g,"$1*$2").replace(/([a-zA-Z)])(\d)/g,"$1*$2"),n=e=>JSON.stringify(Object.entries(e).sort(([e],[t])=>e.localeCompare(t))),o=e=>Object.fromEntries(JSON.parse(e)),i=e=>new Map([[n({}),e]]),a=e=>new Map([...e.entries()].filter(([,e])=>0!==e)),s=(e,t,r=1)=>{const n=new Map(e);for(const[e,o]of t.entries())n.set(e,(n.get(e)||0)+r*o);return a(n)},l=(e,t)=>{const r=new Map;for(const[i,a]of e.entries()){const e=o(i);for(const[i,s]of t.entries()){const t=o(i),l={...e};for(const[e,r]of Object.entries(t))l[e]=(l[e]||0)+r;const u=n(l);r.set(u,(r.get(u)||0)+a*s)}}return a(r)},u=(e,t)=>{let r=i(1);for(let n=0;n<t;n++)r=l(r,e);return r},c=(e,t=i(1))=>({num:e,den:t}),p=(e,t,r=1)=>c(s(l(e.num,t.den),l(t.num,e.den),r),l(e.den,t.den)),m=e=>{switch(e.type){case"Literal":return c(i(e.value));case"Identifier":return c((a=e.name,new Map([[n({[a]:1}),1]])));case"UnaryExpression":if("-"===e.operator)return o=m(e.argument),c(s(new Map,o.num,-1),o.den);throw new Error("Unsupported unary operator");case"BinaryExpression":{const n=m(e.left),o=m(e.right);switch(e.operator){case"+":return p(n,o);case"-":return p(n,o,-1);case"*":return r=o,c(l((t=n).num,r.num),l(t.den,r.den));case"/":return((e,t)=>c(l(e.num,t.den),l(e.den,t.num)))(n,o);case"^":if("Literal"!==e.right.type||!Number.isInteger(e.right.value)||e.right.value<0)throw new Error("Unsupported exponent");return c(u(n.num,e.right.value),u(n.den,e.right.value));default:throw new Error("Unsupported operator in rationalize()")}}default:throw new Error("Unsupported expression in rationalize()")}var t,r,o,a},f=e=>{const t=[...e.entries()].filter(([,e])=>0!==e).sort(([e],[t])=>{const r=o(e),n=o(t),i=Object.keys(r).sort()[0]||"",a=Object.keys(n).sort()[0]||"";if(i!==a)return i.localeCompare(a);const s=Object.values(r).reduce((e,t)=>e+t,0);return Object.values(n).reduce((e,t)=>e+t,0)-s});return t.length?t.map(([e,t],r)=>{const n=o(e),i=Math.abs(t);let a=Object.entries(n).map(([e,t])=>1===t?e:`${e} ^ ${t}`).join(" * ");return a?1!==i&&(a=`${i} * ${a}`):a=`${i}`,0===r?t<0?`- ${a}`.replace("- ","-"):a:t<0?`- ${a}`:`+ ${a}`}).join(" "):"0"},y=this.parse(r).ast,h=m(y),d=f(h.num),v=f(h.den),g=new Set;for(const e of[h.num,h.den])for(const t of e.keys())for(const e of Object.keys(o(t)))g.add(e);return t?{numerator:d,denominator:v,coefficients:[],variables:[...g].sort(),expression:`(${d}) / (${v})`}:`(${d}) / (${v})`})}setVariable(e,t){this.variables.set(e,t)}getVariable(e){return this.variables.get(e)}addFunction(e,t){this.functions.register(e,t)}_createContext(){return s({functions:this.functions,variables:this.variables,units:this.units,evaluate:this.evaluate.bind(this)})}tokenize(e){if("string"!=typeof e)throw new Error("Expression must be a string");return function(e,t={}){const r=[];let n="",o="";const i=["+","-","*","/","%","^","=",">","<","!","&","|"],a=["==",">=","<=","&&","||","+=","-=","*=","/=","%=","?.","??","|>"],s=["to","in"],l=t.units?.getAllUnitsFlat?.()||[],u=e=>!e||"Operator"===e.type||"UnaryOperator"===e.type||"Parenthesis"===e.type&&")"!==e.value||"ArrayStart"===e.type||"Semicolon"===e.type||"Comma"===e.type||"Ternary"===e.type,c=(t,o)=>{if(!n)return;if(/^(true|false)$/i.test(n))return r.push({type:"Boolean",value:"true"===n.toLowerCase()}),void(n="");if(s.includes(n))return r.push({type:"Keyword",value:n,pos:o}),void(n="");if(/^\d+n$/.test(n))return r.push({type:"BigInt",value:BigInt(n.slice(0,-1)),pos:o}),void(n="");if(/^0x[0-9a-fA-F]+$/.test(n))return r.push({type:"Number",value:parseInt(n,16),pos:o}),void(n="");if(/^0b[01]+$/.test(n))return r.push({type:"Number",value:parseInt(n,2),pos:o}),void(n="");if(/^[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?$/i.test(n))return r.push({type:"Number",value:parseFloat(n),pos:o}),void(n="");if(/^[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?i$/i.test(n))return r.push({type:"ImaginaryLiteral",value:parseFloat(n.slice(0,-1)),pos:o}),void(n="");if(/^[+-]?i$/i.test(n)){const e="-"===n[0]?-1:1;return r.push({type:"ImaginaryLiteral",value:e,pos:o}),void(n="")}const i=n.match(/^([+-]?\d+(\.\d+)?)([a-zA-Z]+)$/);if(i){const e=parseFloat(i[1]),t=i[3];return r.push({type:l.includes(t)?"NumberWithUnit":"UnknownUnit",value:e,unit:t,pos:o}),void(n="")}if(l.includes(n)){const{prevWord:i}=function(e,t){const r=e.match(/[a-z0-9]+/gi)||[],n=e[t]||null,o=t>0?e[t-1]:null;let i=t;for(;i>0&&/[a-z0-9]/i.test(e[i-1]);)i--;let a=t;for(;a<e.length&&/[a-z0-9]/i.test(e[a]);)a++;const s=e.substring(i,a),l=r.indexOf(s);return{prevWord:l>0?r[l-1]:null,prevChar:o,currentWord:s,currentChar:n,nextWord:-1!==l&&l<r.length-1?r[l+1]:null}}(e,o);if("("!==t&&i&&(!isNaN(parseFloat(i))||"to"===i||"in"===i))return r.push({type:"Unit",value:n,pos:o}),void(n="")}if(/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(n))return"("===t?r.push({type:"Function",name:n,pos:o}):r.push({type:"Identifier",name:n,pos:o}),void(n="");throw new Error(`Invalid token "${n}" at index ${o}`)};for(let t=0;t<e.length;t++){let s=e[t],l=e[t+1];if("/"===s&&"/"===l){for(;t<e.length&&"\n"!==e[t];)t++;continue}if("/"===s&&"*"===l){for(t+=2;t<e.length&&("*"!==e[t]||"/"!==e[t+1]);)t++;t++;continue}if("\"'".includes(s)){o?o===s?(n+=s,r.push({type:"String",value:n.slice(1,-1),pos:t}),n="",o=""):n+=s:(o=s,n+=s);continue}if(o){n+="\\"===s?s+e[++t]:s;continue}const p=s+l;if(a.includes(p))c(s,t),r.push({type:"Operator",value:p,pos:t}),t++;else if("?"!==s){if(":"===s){c(s,t);const e=r[r.length-1];e&&"Ternary"===e.type?r.push({type:"Ternary",value:":"}):r.push({type:"Colon"});continue}if("."===s&&/\d/.test(n)&&/\d/.test(l))n+=s;else if("."!==s){if(i.includes(s)){c(s,t);const e=r[r.length-1];"-"!==s&&"!"!==s||!u(e)?r.push({type:"Operator",value:s,pos:t}):r.push({type:"UnaryOperator",value:s,pos:t});continue}"()".includes(s)?(c(s,t),r.push({type:"Parenthesis",value:s,pos:t})):"["!==s?"]"!==s?"{"!==s?"}"!==s?","!==s?";"!==s?" "!==s?(n+=s,t===e.length-1&&c(null,t)):c(l,t):(c(s,t),r.push({type:"Semicolon",pos:t})):(c(s,t),r.push({type:"Comma",pos:t})):(c(s,t),r.push({type:"BlockEnd",pos:t})):(c(s,t),r.push({type:"BlockStart",pos:t})):(c(s,t),r.push({type:"ArrayEnd",pos:t})):(c(s,t),r.push({type:"ArrayStart",pos:t}))}else c(s,t),r.push({type:"Dot",pos:t})}else r.push({type:"Ternary",value:"?"})}if(o)throw new Error("Unclosed string literal");const p=[];for(let e=0;e<r.length;e++){const t=r[e],n=r[e+1];"Number"!==t?.type||"Unit"!==n?.type?p.push(t):(p.push({type:"NumberWithUnit",value:t.value,unit:n.value,pos:t.pos}),e++)}const m=[];for(let e=0;e<p.length;e++){const t=p[e],r=p[e+1];m.push(t),t&&r&&(["Number","Identifier"].includes(t.type)||"Parenthesis"===t.type&&")"===t.value||"ArrayEnd"===t.type)&&(["Identifier","Function"].includes(r.type)||"Parenthesis"===r.type&&"("===r.value)&&m.push({type:"Operator",value:"*",implicit:!0})}return m}(e,this._createContext())}parse(e){const t=this.tokenize(e);return{tokens:t,ast:U(t)}}evaluate(e){const{ast:t}=this.parse(e);return I(a(t,this._createContext()))}compile(e){if(this._cache.has(e))return this._cache.get(e);const{ast:t}=this.parse(e),r=(e={})=>{const r=this._createContext().withScope(e);return I(a(t,r))};return this._cache.set(e,r),r}clearCache(){this._cache.clear()}}});
|
|
3
3
|
|