From 8abbac4bc986f86d94c18138774fdd4c60c03039 Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Fri, 16 May 2025 08:51:58 +0200 Subject: [PATCH] Let ... in ... block autocomplete also sorted by best 'match', type-wise --- src/CallBlock.css | 6 ++++++ src/CallBlock.tsx | 33 ++++++--------------------------- src/Editor.tsx | 3 ++- src/LambdaBlock.tsx | 5 ++++- src/LetInBlock.css | 2 +- src/LetInBlock.tsx | 31 +++++++++++++++++++++---------- src/eval.ts | 29 ++++++++++++++++++++++++++--- 7 files changed, 66 insertions(+), 43 deletions(-) diff --git a/src/CallBlock.css b/src/CallBlock.css index 63ae30a..0e3b4ce 100644 --- a/src/CallBlock.css +++ b/src/CallBlock.css @@ -47,6 +47,12 @@ .outputParam > .inputParam > .inputParam > .inputParam:after { border-left-color: rgb(153, 212, 214); } +.outputParam > .inputParam > .inputParam > .inputParam > .inputParam { + background-color: rgb(111, 186, 209); +} +.outputParam > .inputParam > .inputParam > .inputParam > .inputParam:after { + border-left-color: rgb(111, 186, 209); +} .typeAnnot { display: inline-block; diff --git a/src/CallBlock.tsx b/src/CallBlock.tsx index 8472644..f63f58c 100644 --- a/src/CallBlock.tsx +++ b/src/CallBlock.tsx @@ -3,26 +3,23 @@ import { useContext, useInsertionEffect } from "react"; import { Editor, type EditorState } from "./Editor"; import { Value } from "./Value"; import { type SetStateFn, type State2Props } from "./Editor"; -import { evalCallBlock, evalEditorBlock } from "./eval"; +import { evalCallBlock, evalEditorBlock, scoreResolved } from "./eval"; import { type ResolvedType } from "./eval"; import "./CallBlock.css"; import { EnvContext } from "./EnvContext"; import type { SuggestionType } from "./InputBlock"; import { UnifyError } from "dope2"; -export interface CallBlockState< - FnState=EditorState, - InputState=EditorState, -> { +export interface CallBlockState { kind: "call"; - fn: FnState; - input: InputState; + fn: EditorState; + input: EditorState; } interface CallBlockProps< FnState=EditorState, InputState=EditorState, -> extends State2Props,EditorState> { +> extends State2Props { suggestionPriority: (suggestion: SuggestionType) => number; } @@ -110,25 +107,7 @@ export function CallBlockNoSugar({ state, setState, suggestionPriority }: CallBl function computePriority(fn: ResolvedType, input: ResolvedType, outPriority: (s: SuggestionType) => number) { const resolved = evalCallBlock(fn, input); - - const r = outPriority(['literal', '', - // @ts-ignore: // TODO fix this - {t: resolved.t}]); - - if (resolved.kind === "value") { - // 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 - console.log('r:', r); - return 1 + r; - } - else if (resolved.kind === "unknown") { - return 0 + r; - } - if (resolved.e instanceof UnifyError) { - return -1 + r; // parameter doesn't match - } - else { - return -2 + r; // even worse: fn is not a function! - } + return scoreResolved(resolved, outPriority); } function FunctionHeader({ fn, setFn, input, onFnCancel, suggestionPriority }) { diff --git a/src/Editor.tsx b/src/Editor.tsx index 9be2868..1f4495b 100644 --- a/src/Editor.tsx +++ b/src/Editor.tsx @@ -166,7 +166,8 @@ export function Editor({state, setState, onCancel, suggestionPriority}: EditorPr return EditorState)=>void} - />; + suggestionPriority={suggestionPriority} + />; case "lambda": return <>; } diff --git a/src/LambdaBlock.tsx b/src/LambdaBlock.tsx index c742c26..0b8c83e 100644 --- a/src/LambdaBlock.tsx +++ b/src/LambdaBlock.tsx @@ -7,5 +7,8 @@ export interface LambdaBlockState { kind: "lambda"; paramName: string; expr: EditorState; - resolved: ResolvedType; } + +export function LambdaBlock { + +} \ No newline at end of file diff --git a/src/LetInBlock.css b/src/LetInBlock.css index 2762ad9..27cf5f3 100644 --- a/src/LetInBlock.css +++ b/src/LetInBlock.css @@ -1,6 +1,6 @@ .keyword { color: blue; - margin: 0 2px 0 2px; + /* margin: 0 2px 0 2px; */ } diff --git a/src/LetInBlock.tsx b/src/LetInBlock.tsx index 7064975..abd4850 100644 --- a/src/LetInBlock.tsx +++ b/src/LetInBlock.tsx @@ -4,11 +4,12 @@ import { growEnv } from "dope2"; import { Editor, type EditorState } from "./Editor"; import { EnvContext } from "./EnvContext"; -import { evalEditorBlock, type ResolvedType } from "./eval"; +import { evalEditorBlock, evalLetInBlock, scoreResolved, type ResolvedType } from "./eval"; import { type State2Props } from "./Editor"; import { autoInputWidth } from "./util/dom_trickery"; import "./LetInBlock.css"; +import type { SuggestionType } from "./InputBlock"; export interface LetInBlockState { kind: "let"; @@ -17,17 +18,19 @@ export interface LetInBlockState { inner: EditorState; } -interface LetInBlockProps extends State2Props { +interface LetInBlockProps extends State2Props { + suggestionPriority: (suggestion: SuggestionType) => number; } export function makeInnerEnv(env, name: string, value: ResolvedType) { + if (value.kind === "value") { return growEnv(env)(name)(value) } return env; } -export function LetInBlock({state, setState}: LetInBlockProps) { +export function LetInBlock({state, setState, suggestionPriority}: LetInBlockProps) { const {name, value, inner} = state; const env = useContext(EnvContext); const valueResolved = evalEditorBlock(value, env); @@ -47,10 +50,12 @@ export function LetInBlock({state, setState}: LetInBlockProps) { useEffect(() => autoInputWidth(nameRef, name, 60), [nameRef, name]); - + console.log({innerEnv}); + return
let +   - = +  =  0} - onCancel={() => {}} + suggestionPriority={(suggestion: SuggestionType) => { + const innerEnv = makeInnerEnv(env, name, suggestion[2]); + const resolved = evalEditorBlock(inner, innerEnv); + return scoreResolved(resolved, suggestionPriority); + }} + onCancel={() => setState(state => state.inner)} // keep inner /> -  in + in
0} - onCancel={() => {}} + suggestionPriority={(suggestion: SuggestionType) => { + return suggestionPriority(suggestion) + }} + onCancel={() => setState(state => state.value)} // keep value />
diff --git a/src/eval.ts b/src/eval.ts index 4d5a67f..af1859d 100644 --- a/src/eval.ts +++ b/src/eval.ts @@ -38,9 +38,7 @@ export const evalEditorBlock = (s: EditorState, env): ResolvedType => { return evalCallBlock(fn, input); } if (s.kind === "let") { - const value = evalEditorBlock(s.value, env); - const innerEnv = makeInnerEnv(env, s.name, value) - return evalEditorBlock(s.inner, innerEnv); + return evalLetInBlock(s.value, s.name, s.inner, env); } if (s.kind === "lambda") { const expr = evalEditorBlock(s.expr, env); @@ -125,6 +123,12 @@ export function evalCallBlock(fn: ResolvedType, input: ResolvedType): ResolvedTy } } +export function evalLetInBlock(value: EditorState, name: string, inner: EditorState, env) { + const valueResolved = evalEditorBlock(value, env); + const innerEnv = makeInnerEnv(env, name, valueResolved) + return evalEditorBlock(inner, innerEnv); +} + export function haveValue(resolved: ResolvedType) { // return resolved && !(resolved instanceof DeepError); return resolved.kind === "value"; @@ -166,3 +170,22 @@ export function attemptParseLiteral(text: string): Dynamic[] { return literalParsers.map(parseFn => parseFn(text)) .filter(resolved => (resolved.kind !== "unknown" && resolved.kind !== "error")) as unknown as Dynamic[]; } + +export function scoreResolved(resolved: ResolvedType, outPriority) { + const bias = outPriority(['literal', '', + // @ts-ignore: // TODO fix this + {t: resolved.t}]); + + if (resolved.kind === "value") { + return 1 + bias; + } + else if (resolved.kind === "unknown") { + return 0 + bias; + } + if (resolved.e instanceof UnifyError) { + return -1 + bias; // parameter doesn't match + } + else { + return -2 + bias; // even worse: fn is not a function! + } +} \ No newline at end of file