import { useContext } from "react"; import { Editor, type EditorState } from "./Editor"; import { Value } from "./Value"; import { type SetStateFn, type State2Props } from "./Editor"; import { DeepError, evalCallBlock, evalEditorBlock, haveValue } from "./eval"; import { type ResolvedType } from "./eval"; import "./CallBlock.css"; import { EnvContext } from "./EnvContext"; import type { SuggestionType } from "./InputBlock"; import { getType, NotAFunctionError, unify, UnifyError } from "dope2"; export interface CallBlockState< FnState=EditorState, InputState=EditorState, > { kind: "call"; fn: FnState; input: InputState; } interface CallBlockProps< FnState=EditorState, InputState=EditorState, > extends State2Props,EditorState> { suggestionPriority: (suggestion: SuggestionType) => number; } function headlessCallBlock(setState: (callback: SetStateFn) => void) { const setFn = (callback: SetStateFn) => { setState(state => ({...state, fn: callback(state.fn)})); } const setInput = (callback: SetStateFn) => { setState(state => ({...state, input: callback(state.input)})); } const onFnCancel = () => { setState(state => state.input); // we become our input } const onInputCancel = () => { setState(state => state.fn); // we become our function } return {setFn, setInput, onFnCancel, onInputCancel}; } export function CallBlock({ state, setState, suggestionPriority }: CallBlockProps) { const {setFn, setInput, onFnCancel, onInputCancel} = headlessCallBlock(setState); const env = useContext(EnvContext); const resolved = evalEditorBlock(state, env); return
{/* Sequence of input parameters */} {/* Output (or Error) */} { resolved instanceof DeepError && resolved.e.toString() || resolved && <> }
; } function computePriority(fn: ResolvedType, input: ResolvedType, outPriority: (s: SuggestionType) => number) { const resolved = evalCallBlock(fn, input); if ((resolved && !(resolved instanceof DeepError))) { // The computed output becomes an input for the surrounding block, which may also have a priority function defined, for instance our output is the input to another function return 1 + outPriority(['literal', '', resolved]); } return 0; // no fit } function FunctionHeader({ fn, setFn, input, onFnCancel, suggestionPriority }) { const env = useContext(EnvContext); if (fn.kind === "call") { // if the function we're calling is itself the result of a function call, // then we are anonymous, and so we don't draw a function name // recurse: const { setFn : setFnFn, onFnCancel : onFnFnCancel, } = headlessCallBlock(setFn); return computePriority( fnSuggestion[2], evalEditorBlock(fn.input, env), suggestionPriority, )} />; } else { // end of recursion - draw function name return  𝑓𝑛  computePriority( fnSuggestion[2], // suggestions will be for function evalEditorBlock(input, env), // input *may* be set suggestionPriority, // priority function we get from parent block )} /> ; } } function InputParams({ fn, setFn, input, setInput, onInputCancel, depth, errorDepth, suggestionPriority }) { const env = useContext(EnvContext); let nestedParams; if (fn.kind === "call") { // Nest input of nested function const { setFn : setFnFn, setInput : setFnInput, } = headlessCallBlock(setFn); nestedParams = {/*todo*/}} depth={depth+1} errorDepth={errorDepth} suggestionPriority={ (inputSuggestion: SuggestionType) => computePriority( evalEditorBlock(fn.fn, env), inputSuggestion[2], suggestionPriority, )} />; } else { nestedParams = <>; } const isOffending = depth === errorDepth; return
{nestedParams} computePriority( evalEditorBlock(fn, env), // fn *may* be set inputSuggestion[2], // suggestions will be for input suggestionPriority, // priority function we get from parent block )} />
; // {(fn.kind === "call") && // // if the function we're calling is itself the result of a function call, // // then we render its input parameter nested in our own input parameter box, which is way more readable // // recurse: // // } // {/* Our own input */} // computePriority( // evalEditorBlock(fn, env), // fn *may* be set // inputSuggestion[2], // suggestions will be for input // suggestionPriority, // priority function we get from parent block // )} // /> // ; } // function NestedParams({fn, setFn, depth, errorDepth, suggestionPriority}) { // const env = useContext(EnvContext); // const { // setFn : setFnFn, // setInput : setFnInput, // } = headlessCallBlock(setFn); // return {/*todo*/}} // depth={depth+1} // errorDepth={errorDepth} // suggestionPriority={ // (inputSuggestion: SuggestionType) => computePriority( // evalEditorBlock(fn.fn, env), // fn *may* be set // inputSuggestion[2], // suggestions will be for input // suggestionPriority, // priority function we get from parent block // )} // />; // }