import { TokenSymbol , idx , ll1Table , sddTable } from './constant' ; import type { Operations } from './operations' ; import { bigintOperations , decimalOperations , integerOperations , } from './operations' ; export type Calculate < T extends number | bigint > = ( expression : string ) => T ; export function createCalculate < T extends number | bigint > ( operations , resolveExpression ? ) { const { ZERO , parse , add , subtract , multiply , divide } = operations ; return function ( rawExpression ) : T { const expression = resolveExpression == null ? rawExpression : resolveExpression ( rawExpression ) ; let cur = 0 ; const result = execute ( idx ( 'A' ) , ZERO , ZERO ) ; if ( cur === expression . length ) return result ; throw new SyntaxError ( 'Not a valid arithmetic expression.' ) ; function execute ( id , syn , inh ) { if ( cur === expression . length ) { if ( id === TokenSymbol . D || id === TokenSymbol . E ) return inh ; throw new SyntaxError ( 'Not a valid arithmetic expression.' ) ; } const id0 = idx ( expression [ cur ] ) ; if ( id0 === undefined ) { throw new SyntaxError ( `Unrecognized symbol: ${ expression [ cur ] }` ) ; } if ( id === id0 ) { if ( id0 === TokenSymbol . DIGIT ) { const [ nextCur , value ] = parse ( expression , cur ) ; if ( cur >= nextCur ) { throw new SyntaxError ( `Invalid number` ) ; } cur = nextCur ; return value ; } cur += 1 ; return syn ; } if ( id > 0 ) { throw new SyntaxError ( 'Not a valid arithmetic expression.' ) ; } const ssdId = ll1Table [ - id ] [ id0 ] ; if ( ssdId < 0 ) { throw new SyntaxError ( 'Not a valid arithmetic expression.' ) ; } const tokens = sddTable [ ssdId ] ; const syn0 = tokens . length > 0 ? execute ( tokens [ 0 ] , ZERO , ZERO ) : ZERO ; switch ( ssdId ) { case 0 : return execute ( tokens [ 1 ] , ZERO , syn0 ) ; case 1 : { const val1 = execute ( tokens [ 1 ] , ZERO , ZERO ) ; return execute ( tokens [ 2 ] , ZERO , val1 ) ; } case 2 : { const val1 = execute ( tokens [ 1 ] , ZERO , ZERO ) ; return execute ( tokens [ 2 ] , ZERO , subtract ( ZERO , val1 ) ) ; } case 3 : return execute ( tokens [ 1 ] , ZERO , syn0 ) ; case 4 : return syn0 ; case 5 : { const result = execute ( tokens [ 1 ] , ZERO , ZERO ) ; execute ( tokens [ 2 ] , ZERO , ZERO ) ; return result ; } case 6 : { const val1 = execute ( tokens [ 1 ] , ZERO , ZERO ) ; return execute ( tokens [ 2 ] , ZERO , add ( inh , val1 ) ) ; } case 7 : { const val1 = execute ( tokens [ 1 ] , ZERO , ZERO ) ; return execute ( tokens [ 2 ] , ZERO , subtract ( inh , val1 ) ) ; } case 8 : return inh ; case 9 : { const val1 = execute ( tokens [ 1 ] , ZERO , ZERO ) ; return execute ( tokens [ 2 ] , ZERO , multiply ( inh , val1 ) ) ; } case 10 : { const val1 = execute ( tokens [ 1 ] , ZERO , ZERO ) ; return execute ( tokens [ 2 ] , ZERO , divide ( inh , val1 ) ) ; } case 11 : return inh ; default : throw new Error ( 'Shit codes!' ) ; } } } ; } export const calculate = createCalculate < number > ( integerOperations , s => s . replace ( /[\s]+/g , '' ) ) ; export const decimalCalculate = createCalculate < number > ( decimalOperations , s => s . replace ( /[\s]+/g , '' ) . replace ( /(^|[^\d.])\./g , '$10.' ) ) ; export const bigintCalculate = createCalculate < bigint > ( bigintOperations , s => s . replace ( /[\s]+/g , '' ) ) ;