import { IConsumer , IProducer , } from "@tiny-calc/types" ; import { parseExpression , Pending , ExpressionNode , interpret , Primitive , TypeMap , TypeName , CalcFun , CalcObj , CalcValue , } from "@tiny-calc/nano" ; interface Producer extends IProducer < Record < string , Value > > { } type Value = Producer | CalcFun < unknown > | Primitive ; export class Context implements Producer { constructor ( private fields ) { } id = "context" ; close ( ) { } open ( ) { const producer = this ; return { get : ( key ) => this . fields [ key ] , producer } ; } } export class TimeProducer implements Producer { constructor ( ) { } id = "Time" ; close ( ) { } open ( ) { const time = Date . now ( ) ; const producer = this ; return { get : ( ) => time , producer } ; } } type FormulaHost = IConsumer < Record < string , Value > > ; function createPending ( v ) { if ( v . estimate === undefined ) { return { kind : "Pending" } ; } if ( typeof v . estimate === "object" ) { return { kind : "Pending" , estimate : createCalcValue ( v . estimate ) } ; } return { kind : "Pending" , estimate : v . estimate } ; } function createReadMap < O > ( read ) { return { [ TypeName . Readable ] : { read : ( _v , p , c ) => read ( p , c ) } } ; } function createObjFromMap < O > ( map ) { return { typeMap : ( ) => map , serialise : ( ) => "TODO" } ; } function createCalcValue ( v ) { const cache = { } ; const calcVal = createObjFromMap ( createReadMap ( ( message , consumer ) => { if ( cache [ message ] !== undefined ) { return cache [ message ] ; } const value = v . open ( consumer ) . get ( message ) ; switch ( typeof value ) { case "string" : case "number" : case "boolean" : case "function" : return cache [ message ] = value ; default : if ( "kind" in value ) { return createPending ( value ) ; } return cache [ message ] = createCalcValue ( value ) ; } } ) ) ; return calcVal ; } export class ListFormula implements FormulaHost { private formulas : ExpressionNode < string > [ ] ; constructor ( private scope , private formulaText , private withValue ) { this . formulas = [ ] ; const [ errors , formula ] = parseExpression ( this . formulaText ) ; if ( ! errors ) { for ( let i = 0 ; i < 1000000 ; i += 1 ) { this . formulas . push ( formula ) ; } } } keyChanged ( ) { console . time ( "recalc" ) ; const scope = createCalcValue ( this . scope ) ; const values = [ ] ; for ( let i = 0 ; i < 1000000 ; i += 1 ) { values . push ( interpret ( this , scope , this . formulas [ i ] ) ) ; } console . timeEnd ( "recalc" ) ; this . withValue ( values . map ( ( [ _ , v ] ) => v ) ) ; } } export class MathProducer implements Producer { static max = < O > ( _t , _o , [ x , y ] ) => y > x ? y : x ; static min = < O > ( _t , _o , [ x , y ] ) => y < x ? y : x ; constructor ( ) { } id = "Math" ; close ( ) { } open ( ) { const producer = this ; return { get : ( property ) => { switch ( property ) { case "Max" : return MathProducer . max ; case "Min" : return MathProducer . min ; default : return Math . PI ; } } , producer } ; } } export const context = new Context ( { Time : new TimeProducer ( ) , Math : new MathProducer ( ) } ) ;