import { Expression } from '@cortex-js/compute-engine' ; import { getExpressionValue , handleExpressionValue } from './mathjson-utils' ; /**
 * Getters are variables that are being *read*
 */ export function getGetterNames ( expression ) { const getters = new Set < string > ( ) ; function extractGetters ( expression ) { handleExpressionValue ( expression , { symbol : ( v ) => getters . add ( v ) , function : ( v ) => v . args . forEach ( ( u ) => extractGetters ( u ) ) , } ) ; } handleExpressionValue ( expression , { symbol : ( v ) => getters . add ( v ) , function : ( v ) => { if ( v . head === 'Assign' ) { extractGetters ( v . args [ 1 ] ) ; } else if ( v . head === 'Equal' ) { extractGetters ( v . args [ 0 ] ) ; } else if ( v . head === 'Evaluate' ) { extractGetters ( v . args [ 0 ] ) ; } else { extractGetters ( [ v . head , ... v . args ] ) ; } } , } ) ; return getters ; } /**
 * TODO: Actually this does too much. Instead, we want to get all direct getters and then any symbols that the getter might be using
 * Gets all the variables that are being read, including their references, recursively
 */ export function getAllGetterNames ( expression , gettersData ) { const getterNames = new Set < string > ( ) ; const queue = [ ... getGetterNames ( expression ) ] ; while ( queue . length > 0 ) { const name = queue . pop ( ) ; if ( name === undefined ) continue ; if ( getterNames . has ( name ) ) continue ; getterNames . add ( name ) ; const expressionData = gettersData . get ( name ) ; if ( expressionData !== undefined ) { queue . push ( ... getGetterNames ( expressionData ) ) ; } } return getterNames ; } export function useEncoder ( ) { const textEncoder = new TextEncoder ( ) ; const textDecoder = new TextDecoder ( ) ; const charOffset = 'A' . charCodeAt ( 0 ) ; function encodeName ( name ) { const data = textEncoder . encode ( name ) ; let output = '' ; for ( let i = 0 ; i < data . length ; i ++ ) { const highBits = ( data [ i ] >> 4 ) & 0x0f ; const lowBits = data [ i ] & 0x0f ; output += String . fromCharCode ( highBits + charOffset ) + String . fromCharCode ( lowBits + charOffset ) ; } return output ; } function decodeName ( name ) { name = name . slice ( 1 ) ; const output = new Uint8Array ( name . length / 2 ) ; for ( let i = 0 ; i < name . length ; i += 2 ) { const highBits = name . charCodeAt ( i ) - charOffset ; const lowBits = name . charCodeAt ( i + 1 ) - charOffset ; output [ i / 2 ] = ( highBits << 4 ) | lowBits ; } return textDecoder . decode ( output ) ; } return { encodeName , decodeName , } ; }