import { useEffect, useState, useRef } from 'react' import { parse, BinaryPart, Value, executor } from '../lang/wasm' import { createIdentifier, createLiteral, createUnaryExpression, findUniqueName, } from '../lang/modifyAst' import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst' import { useStore } from '../useStore' import { engineCommandManager } from '../lang/std/engineConnection' export const AvailableVars = ({ onVarClick, prevVariables, }: { onVarClick: (a: string) => void prevVariables: PrevVariable[] }) => { return ( ) } export const addToInputHelper = ( inputRef: React.RefObject, setValue: (a: string) => void ) => (varName: string) => { const selectionStart = inputRef.current?.selectionStart let selectionEnd = inputRef.current?.selectionEnd let newValue = '' if ( typeof selectionStart === 'number' && typeof selectionEnd === 'number' ) { newValue = stringSplice( inputRef.current?.value || '', selectionStart, selectionEnd, varName ) selectionEnd = selectionStart + varName.length } else { newValue = inputRef.current?.value + varName } setValue(newValue) inputRef.current?.focus() setTimeout(() => { // run in the next render cycle const _selectionEnd = typeof selectionEnd === 'number' ? selectionEnd : newValue.length inputRef.current?.setSelectionRange(_selectionEnd, _selectionEnd) }) } function stringSplice(str: string, index: number, count: number, add: string) { return str.slice(0, index) + (add || '') + str.slice(index + count) } // what a terriable name export function useCalc({ value, initialVariableName: valueName = '', }: { value: string initialVariableName?: string }): { inputRef: React.RefObject valueNode: Value | null calcResult: string prevVariables: PrevVariable[] newVariableName: string isNewVariableNameUnique: boolean newVariableInsertIndex: number setNewVariableName: (a: string) => void } { const { ast, programMemory, selectionRange, defaultPlanes } = useStore( (s) => ({ ast: s.ast, programMemory: s.programMemory, selectionRange: s.selectionRanges.codeBasedSelections[0].range, defaultPlanes: s.defaultPlanes, }) ) const inputRef = useRef(null) const [availableVarInfo, setAvailableVarInfo] = useState< ReturnType >({ variables: [], insertIndex: 0, bodyPath: [], }) const [valueNode, setValueNode] = useState(null) const [calcResult, setCalcResult] = useState('NAN') const [newVariableName, setNewVariableName] = useState('') const [isNewVariableNameUnique, setIsNewVariableNameUnique] = useState(true) useEffect(() => { setTimeout(() => { inputRef.current && inputRef.current.focus() inputRef.current && inputRef.current.setSelectionRange(0, String(value).length) }, 100) if (ast) { setNewVariableName(findUniqueName(ast, valueName)) } }, []) useEffect(() => { const allVarNames = Object.keys(programMemory.root) if (allVarNames.includes(newVariableName)) { setIsNewVariableNameUnique(false) } else { setIsNewVariableNameUnique(true) } }, [newVariableName]) useEffect(() => { if (!ast || !programMemory || !selectionRange) return const varInfo = findAllPreviousVariables(ast, programMemory, selectionRange) setAvailableVarInfo(varInfo) }, [ast, programMemory, selectionRange]) useEffect(() => { try { const code = `const __result__ = ${value}\nshow(__result__)` const ast = parse(code) const _programMem: any = { root: {}, return: null } availableVarInfo.variables.forEach(({ key, value }) => { _programMem.root[key] = { type: 'userVal', value, __meta: [] } }) if (!defaultPlanes) return executor(ast, _programMem, engineCommandManager, defaultPlanes!).then( (programMemory) => { const resultDeclaration = ast.body.find( (a) => a.type === 'VariableDeclaration' && a.declarations?.[0]?.id?.name === '__result__' ) const init = resultDeclaration?.type === 'VariableDeclaration' && resultDeclaration?.declarations?.[0]?.init const result = programMemory?.root?.__result__?.value setCalcResult(typeof result === 'number' ? String(result) : 'NAN') init && setValueNode(init) } ) } catch (e) { setCalcResult('NAN') setValueNode(null) } }, [value]) return { valueNode, calcResult, prevVariables: availableVarInfo.variables, newVariableInsertIndex: availableVarInfo.insertIndex, newVariableName, isNewVariableNameUnique, setNewVariableName, inputRef, } } export const CalcResult = ({ calcResult }: { calcResult: string }) => { return (
= {calcResult}
) } export const CreateNewVariable = ({ newVariableName, isNewVariableNameUnique, setNewVariableName, shouldCreateVariable, setShouldCreateVariable = () => {}, showCheckbox = true, }: { isNewVariableNameUnique: boolean newVariableName: string setNewVariableName: (a: string) => void shouldCreateVariable?: boolean setShouldCreateVariable?: (a: boolean) => void showCheckbox?: boolean }) => { return ( <>
{showCheckbox && ( { setShouldCreateVariable(e.target.checked) }} /> )} { setNewVariableName(e.target.value) }} />
{!isNewVariableNameUnique && (
Sorry, that's not a unique variable name. Please try something else
)} ) } export function removeDoubleNegatives( valueNode: BinaryPart, sign: number, variableName?: string ): BinaryPart { let finValue: BinaryPart = variableName ? createIdentifier(variableName) : valueNode if (sign === -1) finValue = createUnaryExpression(finValue) if ( finValue.type === 'UnaryExpression' && finValue.operator === '-' && finValue.argument.type === 'UnaryExpression' && finValue.argument.operator === '-' ) { finValue = finValue.argument.argument } if ( finValue.type === 'UnaryExpression' && finValue.operator === '-' && finValue.argument.type === 'Literal' && typeof finValue.argument.value === 'number' && finValue.argument.value < 0 ) { finValue = createLiteral(-finValue.argument.value) } return finValue }