/** Bounded arithmetic grammar, never JavaScript evaluation. IEEE-754 semantics. */ export function arithmeticExpression(input) { if(typeof input!=='string'||input.length>1000)throw Error('EXPRESSION_BUDGET'); const tokens=input.match(/Infinity|NaN|(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?|\*\*|[()+*/%-]|\S/g)||[]; if(tokens.length>256)throw Error('TOKEN_BUDGET'); let at=0,depth=0; const take=()=>tokens[at++]; function atom(){ if(++depth>32)throw Error('DEPTH_BUDGET'); let value; if(tokens[at]==='('){take();value=sum();if(take()!==')')throw Error('MISSING_PAREN');} else { const token=take(); if(!token||! /^(?:Infinity|NaN|(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)$/.test(token))throw Error('EXPECTED_NUMBER'); value=Number(token); } depth--;return value; } function power(){let v=atom();if(tokens[at]==='**'){take();v=v**unary();}return v;} function unary(){ if(tokens[at]==='+'||tokens[at]==='-'){ const sign=take(); if(tokens[at]===sign)throw Error('INCREMENT_NOT_ARITHMETIC'); // JavaScript forbids a unary expression as the unparenthesized left of **. if(tokens[at]!=='(' && tokens[at+1]==='**')throw Error('UNARY_EXPONENT_BASE'); if(++depth>32)throw Error('DEPTH_BUDGET'); const value=unary();depth--; return sign==='-'?-value:value; } return power(); } function product(){let v=unary();while(['*','/','%'].includes(tokens[at])){const op=take(),r=unary();v=op==='*'?v*r:op==='/'?v/r:v%r;}return v;} function sum(){let v=product();while(['+','-'].includes(tokens[at])){const op=take();if(tokens[at]===op)throw Error('INCREMENT_NOT_ARITHMETIC');const r=product();v=op==='+'?v+r:v-r;}return v;} const value=sum();if(at!==tokens.length)throw Error('UNSUPPORTED_EXPRESSION');return value; }