From fdbf43a4e96e85bbb9dc8b0d71f7b6ce387db1d7 Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Tue, 20 May 2025 15:35:39 +0200 Subject: [PATCH] refactor a bit more --- src/App.tsx | 6 +----- src/CallBlock.tsx | 47 ++++++++++++++++++++------------------------- src/CallContext.ts | 7 +++++++ src/ExprBlock.tsx | 8 +------- src/Input.tsx | 26 ++++++++----------------- src/InputBlock.tsx | 22 ++++++++++++++------- src/LambdaBlock.tsx | 6 +----- src/LetInBlock.tsx | 11 ++--------- src/Value.tsx | 8 +++++++- src/actions.ts | 4 ++-- src/eval.ts | 24 +++++++++++++---------- 11 files changed, 79 insertions(+), 90 deletions(-) create mode 100644 src/CallContext.ts diff --git a/src/App.tsx b/src/App.tsx index 53e2171..2f620e8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,8 +3,7 @@ import './App.css'; import { ExprBlock, type ExprBlockState } from './ExprBlock'; import { GlobalContext } from './GlobalContext'; import { biggerExample, higherOrder, higherOrder2Params, inc, initialEditorState, lambda2Params, nonEmptyEditorState, pushBool, tripleFunctionCallEditorState } from "./configurations"; -import { removeFocus } from "./eval"; -import { actionShortcuts, getActions } from './actions'; +import { actionShortcuts } from './actions'; const examples: [string, ExprBlockState][] = [ @@ -168,9 +167,6 @@ export function App() { // console.log('suggestionPriority of App, always 0'); return 0; }} - addParam={() => { - getActions({doHighlight}, pushHistory).c(); - }} /> diff --git a/src/CallBlock.tsx b/src/CallBlock.tsx index 9650b35..05f868b 100644 --- a/src/CallBlock.tsx +++ b/src/CallBlock.tsx @@ -8,6 +8,8 @@ import { Value } from "./Value"; import "./CallBlock.css"; import { initialEditorState } from "./configurations"; +import { CallContext } from "./CallContext"; +import { getActions } from "./actions"; export interface CallBlockState { kind: "call"; @@ -55,31 +57,26 @@ function nestedInputProperties({state, setState, suggestionPriority}: CallBlockP export function CallBlock(props: CallBlockProps) { const env = useContext(EnvContext); const globalContext = useContext(GlobalContext); - const addParam = (s: ExprBlockState) => { - props.setState(state => ({ - kind: "call", - fn: removeFocus(state), - input: s, - })); - globalContext?.doHighlight.call(); - }; + const addParam = getActions(globalContext, props.setState).c; const [resolved] = evalEditorBlock(props.state, env); return - -
-
- {/* Sequence of input parameters */} - - { (resolved.kind === "error") && resolved.e.toString() - || (resolved.kind === "value") && - || "unknown" } + + +
+
+ {/* Sequence of input parameters */} + + { (resolved.kind === "error") && resolved.e.toString() + || (resolved.kind === "value") && + || "unknown" } +
-
+ ; } @@ -102,12 +99,12 @@ function FunctionHeader(props) { // end of recursion - draw function name return  𝑓𝑛  - + ; } } -function InputParams({ depth, errorDepth, addParam, ...rest }) { +function InputParams({ depth, errorDepth, ...rest }) { const env = useContext(EnvContext); const globalContext = useContext(GlobalContext); const isOffending = depth === errorDepth; @@ -118,12 +115,10 @@ function InputParams({ depth, errorDepth, addParam, ...rest }) { {...nestedFnProperties(rest as CallBlockProps, env)} depth={depth+1} errorDepth={errorDepth} - addParam={addParam} />} {/* Our own input param */}
; } diff --git a/src/CallContext.ts b/src/CallContext.ts new file mode 100644 index 0000000..00d1f12 --- /dev/null +++ b/src/CallContext.ts @@ -0,0 +1,7 @@ +import { createContext } from "react"; + +interface ICallContext { + addParam?: () => void; +} + +export const CallContext = createContext({}); diff --git a/src/ExprBlock.tsx b/src/ExprBlock.tsx index b4250e7..f10e158 100644 --- a/src/ExprBlock.tsx +++ b/src/ExprBlock.tsx @@ -31,10 +31,9 @@ export interface State2Props { interface ExprBlockProps extends State2Props { onCancel: () => void; - addParam: (e: ExprBlockState) => void; } -export function ExprBlock({state, setState, suggestionPriority, onCancel, addParam}: ExprBlockProps) { +export function ExprBlock({state, setState, suggestionPriority, onCancel}: ExprBlockProps) { const env = useContext(EnvContext); const globalContext = useContext(GlobalContext); @@ -44,7 +43,6 @@ export function ExprBlock({state, setState, suggestionPriority, onCancel, addPar setState={setState as (callback:(p:InputBlockState)=>ExprBlockState)=>void} suggestionPriority={suggestionPriority} onCancel={onCancel} - addParam={addParam} />, call: () => ExprBlockState)=>void} suggestionPriority={suggestionPriority} - addParam={addParam} />, lambda: () => ExprBlockState)=>void} suggestionPriority={suggestionPriority} - addParam={addParam} />, }; @@ -79,11 +75,9 @@ export function ExprBlock({state, setState, suggestionPriority, onCancel, addPar placeholder="" text="" suggestion="" - focus={false} onEnter={() => {}} onCancel={onCancel} onTextChange={() => {}} - setFocus={() => {}} extraHandlers={extraHandlers} />
; diff --git a/src/Input.tsx b/src/Input.tsx index 3065297..b015dd9 100644 --- a/src/Input.tsx +++ b/src/Input.tsx @@ -5,8 +5,6 @@ interface InputProps { text: string; suggestion: string; onTextChange: (text: string) => void; - focus: boolean; - setFocus: (focus: boolean) => void; onEnter: () => void; onCancel: () => void; @@ -57,22 +55,14 @@ function focusPrevElement() { } } -export function Input({placeholder, text, suggestion, onTextChange, focus, setFocus, onEnter, onCancel, extraHandlers, children}: InputProps) { +export function Input({placeholder, text, suggestion, onTextChange, onEnter, onCancel, extraHandlers, children}: InputProps) { const ref = useRef(null); - const [hideChildren, setHideChildren] = useState(false); - - useEffect(() => { - if (focus) { - ref.current?.focus(); - setHideChildren(false); - } - }, [focus]); + const [focus, setFocus] = useState<"yes"|"hide"|"no">("no"); useEffect(() => autoInputWidth(ref, (text+(focus?suggestion:'')) || placeholder), [ref, text, suggestion, focus]); const onKeyDown = (e: KeyboardEvent) => { - setHideChildren(false); - + setFocus("yes"); const keys = { // auto-complete Tab: () => { @@ -123,8 +113,8 @@ export function Input({placeholder, text, suggestion, onTextChange, focus, setFo }, Escape: () => { - if (!hideChildren) { - setHideChildren(true); + if (focus === "yes") { + setFocus("hide"); e.preventDefault(); } }, @@ -138,7 +128,7 @@ export function Input({placeholder, text, suggestion, onTextChange, focus, setFo }; return - {focus && !hideChildren && children} + {(focus === "yes") && children} {text}{focus && suggestion} setFocus(true)} - onBlur={() => setFocus(false)} + onFocus={() => setFocus("yes")} + onBlur={() => setFocus("no")} spellCheck={false} /> ; diff --git a/src/InputBlock.tsx b/src/InputBlock.tsx index 48ba4cc..e6ecd8d 100644 --- a/src/InputBlock.tsx +++ b/src/InputBlock.tsx @@ -10,6 +10,9 @@ import type { ExprBlockState, State2Props } from "./ExprBlock"; import { attemptParseLiteral } from "./eval"; import { Input } from "./Input"; import { initialEditorState } from "./configurations"; +import { CallContext } from "./CallContext"; +import { getActions } from "./actions"; +import { GlobalContext } from "./GlobalContext"; interface Literal { kind: "literal"; @@ -35,7 +38,6 @@ export type PrioritizedSuggestionType = [number, ...SuggestionType]; interface InputBlockProps extends State2Props { onCancel: () => void; - addParam: (e: ExprBlockState) => void; } const computeSuggestions = (text, env, suggestionPriority: (s: ResolvedType) => number): PrioritizedSuggestionType[] => { @@ -61,9 +63,11 @@ const computeSuggestions = (text, env, suggestionPriority: (s: ResolvedType) => .sort(([priorityA], [priorityB]) => priorityB - priorityA) } -export function InputBlock({ state, setState, suggestionPriority, onCancel, addParam }: InputBlockProps) { +export function InputBlock({ state, setState, suggestionPriority, onCancel }: InputBlockProps) { const {text, focus} = state; + const globalContext = useContext(GlobalContext); const env = useContext(EnvContext); + const callContext = useContext(CallContext); const inputRef = useRef(null); const [i, setI] = useState(0); // selected suggestion idx @@ -121,7 +125,13 @@ export function InputBlock({ state, setState, suggestionPriority, onCancel, addP }, " ": (e) => { if (text.length > 0) { - addParam(initialEditorState); + if (callContext.addParam) { + callContext.addParam(); + } + else { + const actions = getActions(globalContext, setState); + actions.c(); + } } e.preventDefault(); }, @@ -129,8 +139,6 @@ export function InputBlock({ state, setState, suggestionPriority, onCancel, addP return setState(state => ({...state, focus}))} onCancel={onCancel} onEnter={onSelectSuggestion} onTextChange={onTextChange} @@ -138,12 +146,12 @@ export function InputBlock({ state, setState, suggestionPriority, onCancel, addP suggestion={singleSuggestion} extraHandlers={extraHandlers} > - {focus && + - } + } diff --git a/src/LambdaBlock.tsx b/src/LambdaBlock.tsx index 906d16c..d8a2a7a 100644 --- a/src/LambdaBlock.tsx +++ b/src/LambdaBlock.tsx @@ -21,11 +21,10 @@ interface LambdaBlockProps< FnState=ExprBlockState, InputState=ExprBlockState, > extends State2Props { - addParam: (e: ExprBlockState) => void; } -export function LambdaBlock({state, setState, suggestionPriority, addParam}: LambdaBlockProps) { +export function LambdaBlock({state, setState, suggestionPriority}: LambdaBlockProps) { const env = useContext(EnvContext); const setParamName = paramName => setState(state => ({ @@ -59,11 +58,9 @@ export function LambdaBlock({state, setState, suggestionPriority, addParam}: Lam placeholder="" text={state.paramName} suggestion="" - focus={state.focus} onEnter={() => {}} onCancel={() => {}} onTextChange={txt => setParamName(txt)} - setFocus={focus => setState(state => ({...state, focus}))} extraHandlers={{}} /> @@ -83,7 +80,6 @@ export function LambdaBlock({state, setState, suggestionPriority, addParam}: Lam // console.log('suggestionPriority of lambdaInner... just passing through'); return suggestionPriority(s); }} - addParam={addParam} /> diff --git a/src/LetInBlock.tsx b/src/LetInBlock.tsx index 1f97681..491471c 100644 --- a/src/LetInBlock.tsx +++ b/src/LetInBlock.tsx @@ -18,7 +18,6 @@ export interface LetInBlockState { } interface LetInBlockProps extends State2Props { - addParam: (e: ExprBlockState) => void; } export function LetInBlock(props: LetInBlockProps) { @@ -32,7 +31,7 @@ export function LetInBlock(props: LetInBlockProps) { } -function DeclColumns({state: {name, value, inner, focus}, setState, suggestionPriority, addParam}) { +function DeclColumns({state: {name, value, inner, focus}, setState, suggestionPriority}) { const env = useContext(EnvContext); const globalContext = useContext(GlobalContext); @@ -55,11 +54,9 @@ function DeclColumns({state: {name, value, inner, focus}, setState, suggestionPr placeholder="" text={name} suggestion="" - focus={focus} onEnter={() => {}} onCancel={() => {}} onTextChange={name => setState(state => ({...state, name}))} - setFocus={focus => setState(state => ({...state, focus}))} extraHandlers={{}} /> @@ -70,7 +67,6 @@ function DeclColumns({state: {name, value, inner, focus}, setState, suggestionPr setState={setValue} suggestionPriority={valueSuggestionPriority} onCancel={() => setState(state => state.inner)} // keep inner - addParam={addParam} /> {inner.kind === "let" && @@ -80,14 +76,13 @@ function DeclColumns({state: {name, value, inner, focus}, setState, suggestionPr state={inner} setState={setInner} suggestionPriority={suggestionPriority} - addParam={addParam} /> } ; } -function InnerMost({state, setState, suggestionPriority, addParam}) { +function InnerMost({state, setState, suggestionPriority}) { const env = useContext(EnvContext); const globalContext = useContext(GlobalContext); const setInner = callback => setState(state => ({...state, inner: callback(state.inner)})); @@ -100,7 +95,6 @@ function InnerMost({state, setState, suggestionPriority, addParam}) { state={state.inner} setState={setInner} suggestionPriority={suggestionPriority} - addParam={addParam} /> ; } @@ -111,7 +105,6 @@ function InnerMost({state, setState, suggestionPriority, addParam}) { setState={setInner} suggestionPriority={suggestionPriority} onCancel={onCancel} // keep value - addParam={addParam} /> } diff --git a/src/Value.tsx b/src/Value.tsx index 47db1dd..d708f8f 100644 --- a/src/Value.tsx +++ b/src/Value.tsx @@ -1,4 +1,4 @@ -import {getType, getInst, getSymbol, Double, Int, symbolFunction, symbolProduct, symbolSum, symbolDict, symbolSet, symbolList, eqType, match, getLeft, getRight, dict, Bool, set, Unit, symbolType, symbolUUID, getHumanReadableName} from "dope2"; +import {getType, getInst, getSymbol, Double, Int, symbolFunction, symbolProduct, symbolSum, symbolDict, symbolSet, symbolList, eqType, match, getLeft, getRight, dict, Bool, set, Unit, symbolType, symbolUUID, getHumanReadableName, Ordering} from "dope2"; import "./Value.css"; import { Type } from "./Type"; @@ -18,6 +18,9 @@ export function Value({dynamic}) { if (eqType(type)(Unit)) { return ; } + if (eqType(type)(Ordering)) { + return ; + } const symbol = getSymbol(type); switch (symbol) { @@ -81,4 +84,7 @@ function ValueUnit() { } function ValueUUID({val}) { return {getHumanReadableName(val)}; +} +function ValueOrdering({val}) { + return {{[-1]: "LessThan", [0]: "Equal", [1]: "GreaterThan" }[val]} } \ No newline at end of file diff --git a/src/actions.ts b/src/actions.ts index dd77a0f..8510b0e 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -3,7 +3,7 @@ import { removeFocus } from "./eval"; export const actionShortcuts: [string, string[], string][] = [ ["call" , ['c'], "expr ⌴" ], - ["transform", ['.'], "⌴ expr" ], + ["transform", ['t'], "⌴ expr" ], ["assign" , ['a'], "let (⌴ = expr) in ⌴"], ["declare" , ['d'], "let (⌴ = ⌴) in expr"], ["lambda" , ['l'], "λ⌴. expr" ], @@ -19,7 +19,7 @@ export function getActions(globalContext, setState) { })); globalContext?.doHighlight.call(); }, - '.': () => { + t: () => { setState(state => ({ kind: "call", fn: initialEditorState, diff --git a/src/eval.ts b/src/eval.ts index 34ddb8b..33adff0 100644 --- a/src/eval.ts +++ b/src/eval.ts @@ -1,4 +1,4 @@ -import { Double, fnType, getHumanReadableName, getSymbol, Int, mergeUnifications, NotAFunctionError, occurring, prettyT, prettyU, recomputeTypeVars, reduceUnification, substitute, symbolFunction, trie, TYPE_VARS, UNBOUND_SYMBOLS, UnifyError, unifyLL, transitivelyGrow, isTypeVar, set, compareTypes, recomputeTypeVarsWithInverse } from "dope2"; +import { Double, fnType, getHumanReadableName, getSymbol, Int, isTypeVar, mergeUnifications, NotAFunctionError, occurring, prettyT, prettyU, recomputeTypeVarsWithInverse, reduceUnification, substitute, symbolFunction, trie, TYPE_VARS, UNBOUND_SYMBOLS, UnifyError, unifyLL } from "dope2"; import type { ExprBlockState } from "./ExprBlock"; import type { InputValueType } from "./InputBlock"; @@ -90,13 +90,15 @@ export function evalInputBlock(text: string, value: InputValueType, env: Environ export function evalCallBlock(fn: ExprBlockState, input: ExprBlockState, env: Environment): [ResolvedType,Environment] { const [fnResolved, env2] = evalEditorBlock(fn, env); const [inputResolved, env3] = evalEditorBlock(input, env2); - console.log('==== evalCallBlock ===='); - console.log('env :', env); - console.log('fnResolved :', fnResolved); - console.log('env2 :', env2); - console.log('inputResolved:', inputResolved); - console.log('env3 :', env3); - console.log('======================='); + if (VERBOSE) { + console.log('==== evalCallBlock ===='); + console.log('env :', env); + console.log('fnResolved :', fnResolved); + console.log('env2 :', env2); + console.log('inputResolved:', inputResolved); + console.log('env3 :', env3); + console.log('======================='); + } return evalCallBlock2(fnResolved, inputResolved, env3); } @@ -236,7 +238,7 @@ function evalCallBlock3(fnResolved: ResolvedType, inputResolved: ResolvedType, e // if the above statement did not throw => types are compatible... if (inputResolved.kind === "value" && fnResolved.kind === "value") { const outValue = fnResolved.i(inputResolved.i); - console.log('outValue:', outValue); + // console.log('outValue:', outValue); return [{ kind: "value", i: outValue, @@ -255,7 +257,9 @@ function evalCallBlock3(fnResolved: ResolvedType, inputResolved: ResolvedType, e } catch (e) { // if ((e instanceof UnifyError)) { - console.log('UnifyError!', (e as Error).message); + if (VERBOSE) { + console.log('UnifyError!', (e as Error).message); + } // even though fn was incompatible with the given parameter, we can still suppose that our output-type will be that of fn...? const outType = fnResolved.t.params[1](fnResolved.t); try {