import { OctaveLogger } from '../OctaveLogger' ; import { CommandInterface } from '../Commands' ; import * as Constants from '../Constants' ; import { Variable } from './Variable' ; export class Variables { private static readonly _EMPTY_ARRAY = new Array < Variable > ( ) ; private static readonly _FACTORIES = new Array < Variable > ( ) ; private static readonly _REFS = new Array < Variable > ( ) ; private static _CHUNKS_PREFETCH = Constants . CHUNKS_PREFETCH ; private static _FALLBACK : Variable ; public static evaluateAns = false ; public static setChunkPrefetch ( n ) { if ( n > 0 ) { Variables . _CHUNKS_PREFETCH = n ; } } public static getMaximumElementsPrefetch ( ) { return Variables . _CHUNKS_PREFETCH * Constants . CHUNKS_SIZE ; } public static register ( factory ) { Variables . _FACTORIES . push ( factory ) ; } public static registerFallback ( factory ) { Variables . _FALLBACK = factory ; } public static addReferenceTo ( v ) { v . setReference ( Variables . _REFS . length + 1 ) ; Variables . _REFS . push ( v ) ; } public static getByReference ( reference ) { if ( reference > 0 ) { const index = reference - 1 ; if ( index < Variables . _REFS . length ) { return Variables . _REFS [ index ] ; } } else { OctaveLogger . error ( `Error: getVariable(${ reference })!` ) ; } return null ; } public static clearReferences ( ) { Variables . _REFS . length = 0 ; } public static listByReference ( ref , runtime , count , start , callback ) { const variable = Variables . getByReference ( ref ) ; if ( variable !== null ) { variable . listChildren ( runtime , count , start , callback ) ; } else { OctaveLogger . error ( `Error: listByReference invalid reference ${ ref }` ) ; callback ( Variables . _EMPTY_ARRAY ) ; } } private static skipVariable ( name ) { return ! Variables . evaluateAns && name === 'ans' ; } public static listVariables ( names , runtime , callback ) { const variables = new Array < Variable > ( ) ; let skipped = 0 ; names . forEach ( name => { Variables . loadVariable ( name , runtime , ( v ) => { if ( v === null ) { if ( ! Variables . skipVariable ( name ) ) { OctaveLogger . error ( `Error: could not load variable '${ name }'!` ) ; } ++ skipped ; } else { variables . push ( v ) ; } if ( variables . length + skipped === names . length ) { callback ( variables ) ; } } ) ; } ) ; } public static loadVariable ( name , runtime , callback ) { if ( ! Variables . skipVariable ( name ) ) { Variables . getType ( name , runtime , ( type ) => { for ( let i = 0 ; i !== Variables . _FACTORIES . length ; ++ i ) { const factory = Variables . _FACTORIES [ i ] ; if ( factory . loads ( type ) ) { factory . loadNew ( name , type , runtime , callback ) ; return ; } } if ( Variables . _FALLBACK !== null && Variables . _FALLBACK . loads ( type ) ) { Variables . _FALLBACK . loadNew ( name , type , runtime , callback ) ; } else { callback ( null ) ; } } ) ; } else { callback ( null ) ; } } public static setVariable ( name , value , runtime , callback ) { runtime . evaluateAsLine ( `${ name } = ${ value }` , ( result ) => { Variables . getValue ( name , runtime , callback ) ; } ) ; } private static readonly CLEAN_REGEX = /^\s*ans =\s*/ ; public static clean ( value ) { return value . replace ( Variables . CLEAN_REGEX , '' ) . trim ( ) ; } public static getType ( variable , runtime , callback ) { runtime . evaluateAsLine ( `typeinfo(${ variable })` , ( value ) => { callback ( Variables . clean ( value ) ) ; } ) ; } public static getValue ( variable , runtime , callback ) { runtime . evaluateAsLine ( variable , ( value ) => { callback ( Variables . removeName ( variable , value ) ) ; } ) ; } public static getSize ( variable , runtime , callback ) { runtime . evaluateAsLine ( `size(${ variable })` , ( value ) => { const values = Variables . clean ( value ) . split ( ' ' ) . filter ( ( val ) => val ) ; const size = values . map ( i => parseInt ( i ) ) ; callback ( size ) ; } ) ; } public static getNonZero ( variable , runtime , callback ) { runtime . evaluateAsLine ( `nnz(${ variable })` , ( value ) => { callback ( parseInt ( Variables . clean ( value ) ) ) ; } ) ; } private static readonly ESCAPE_REGEX = /[.*+?^${}()|[\]\\]/g ; public static escape ( str ) { return str . replace ( Variables . ESCAPE_REGEX , '\\$&' ) ; } public static removeName ( name , value ) { name = Variables . escape ( name . trim ( ) ) ; value = value . replace ( new RegExp ( `^\\s*(?:ans|${ name }) =(?:\n\n)?\\s*` ) , '' ) ; return value . trim ( ) ; } public static loadable ( sizes , count = 0 ) { const N = sizes . reduce ( ( acc , val ) => acc *= val , 1 ) ; if ( count !== 0 ) { return sizes . length <= 1 && N * count <= Variables . getMaximumElementsPrefetch ( ) ; } return sizes . length <= 2 && N <= Variables . getMaximumElementsPrefetch ( ) ; } }