suggestions work again, improve error reporting
This commit is contained in:
parent
9050581a10
commit
69175c8cb1
12 changed files with 259 additions and 282 deletions
|
|
@ -1,7 +1,6 @@
|
|||
import { useContext } from "react";
|
||||
|
||||
import { EnvContext } from "../../context/EnvContext";
|
||||
// import { addFocusRightMost, evalCallBlock2, evalExprBlock, recomputeTypeVarsForEnv, scoreResolved, type Environment, type ResolvedType } from "./eval";
|
||||
import { ExprBlock, type ExprBlockState, type SetStateFn, type State2Props } from "./ExprBlock";
|
||||
import { GlobalContext } from "../../context/GlobalContext";
|
||||
|
||||
|
|
@ -30,11 +29,7 @@ function nestedFnProperties({state, setState, score}: CallBlockProps, env: Envir
|
|||
setState(state => state.input); // we become our input
|
||||
};
|
||||
const scoreFn = (fnSuggestion: ExprBlockState) => {
|
||||
return score({
|
||||
kind: "call",
|
||||
fn: fnSuggestion,
|
||||
input: state.input,
|
||||
});
|
||||
return score({ ...state, fn: fnSuggestion });
|
||||
};
|
||||
return {state: state.fn, setState: setFn, onCancel: onFnCancel, score: scoreFn};
|
||||
}
|
||||
|
|
@ -47,24 +42,11 @@ function nestedInputProperties({state, setState, score}: CallBlockProps, env: En
|
|||
setState(state => /*addFocusRightMost*/(state.fn)); // we become our function
|
||||
};
|
||||
const scoreInput = (inputSuggestion: ExprBlockState) => {
|
||||
return score({
|
||||
kind: "call",
|
||||
fn: state.fn,
|
||||
input: inputSuggestion,
|
||||
});
|
||||
return score({ ...state, input: inputSuggestion });
|
||||
};
|
||||
return {state: state.input, setState: setInput, onCancel: onInputCancel, score: scoreInput};
|
||||
}
|
||||
|
||||
// function computePriority(fn: ResolvedType, input: ResolvedType, outPriority: (s: ResolvedType) => number, env) {
|
||||
// // dirty, but works:
|
||||
// const [fnR, env2] = recomputeTypeVarsForEnv('<fn>', fn, env);
|
||||
// const [inR, env3] = recomputeTypeVarsForEnv('<in>', input, env2);
|
||||
// const [resolved] = evalCallBlock2(fnR, inR, env3);
|
||||
// const score = scoreResolved(resolved, outPriority);
|
||||
// return score;
|
||||
// }
|
||||
|
||||
export function CallBlock(props: CallBlockProps) {
|
||||
const env = useContext(EnvContext);
|
||||
const globalContext = useContext(GlobalContext);
|
||||
|
|
@ -80,9 +62,6 @@ export function CallBlock(props: CallBlockProps) {
|
|||
{/* Sequence of input parameters */}
|
||||
<InputParams
|
||||
{...props}
|
||||
depth={0}
|
||||
// errorDepth={(resolved.kind === "error") ? (resolved.depth) : -1}
|
||||
errorDepth={-1}
|
||||
addParam={addParam}
|
||||
/>
|
||||
{/* { (resolved.kind === "error") && resolved.e.toString()
|
||||
|
|
@ -113,20 +92,20 @@ function FunctionHeader(props) {
|
|||
}
|
||||
}
|
||||
|
||||
function InputParams({ depth, errorDepth, ...rest }) {
|
||||
function InputParams({ ...rest }) {
|
||||
const env = useContext(EnvContext);
|
||||
const globalContext = useContext(GlobalContext);
|
||||
const isOffending = depth === errorDepth;
|
||||
const typeInfo = inferTypeCall(rest.state, env);
|
||||
const inputEnv = typeInfo.fn.newEnv;
|
||||
const isOffending = rest.state.err;
|
||||
return <div className={"inputParam" + (isOffending ? " offending" : "")}>
|
||||
{rest.state.fn.kind === "call"
|
||||
&& globalContext?.syntacticSugar
|
||||
&& <InputParams
|
||||
{...nestedFnProperties(rest as CallBlockProps, env)}
|
||||
depth={depth+1}
|
||||
errorDepth={errorDepth}
|
||||
/>}
|
||||
{/* Our own input param */}
|
||||
<EnvContext value={inferTypeCall(rest.state, env).inputEnv}>
|
||||
<EnvContext value={inputEnv}>
|
||||
<ExprBlock
|
||||
{...nestedInputProperties(rest as CallBlockProps, env)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { useContext } from "react";
|
||||
|
||||
import { getType } from "dope2";
|
||||
|
||||
import { CallBlock, type CallBlockProps, type CallBlockState } from "./CallBlock";
|
||||
import { EnvContext } from "../../context/EnvContext";
|
||||
import { GlobalContext } from "../../context/GlobalContext";
|
||||
|
|
@ -13,6 +11,7 @@ import { LetInBlock, type LetInBlockProps, type LetInBlockState } from "./LetInB
|
|||
import "./ExprBlock.css";
|
||||
import { Input } from "../other/Input";
|
||||
import { getActions } from "../app/actions";
|
||||
import { inferType, type Type } from "../../eval/infer_type";
|
||||
|
||||
export type ExprBlockState =
|
||||
InputBlockState
|
||||
|
|
@ -49,16 +48,14 @@ export function ExprBlock(props: ExprBlockProps) {
|
|||
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
||||
[shortcut, (e) => { e.preventDefault(); action(); }]))
|
||||
|
||||
// return <span className={"editor" + ((resolved.kind!=="value") ? " "+resolved.kind : "")}>
|
||||
const typeInfo = inferType(props.state, env);
|
||||
|
||||
return <span className={"editor"}>
|
||||
return <span className={"editor" + (typeInfo.err ? " error" : "")}>
|
||||
{renderBlock[props.state.kind]()}
|
||||
{/* @ts-ignore */}
|
||||
{/* <div className={"typeSignature" + (resolved.__debug ? ' gotDebug' : '')}> */}
|
||||
{/* :: <Type type={typeInfo.type} /> */}
|
||||
{/* @ts-ignore */}
|
||||
{/* {resolved.__debug && <div className="typeDebug">{resolved.__debug}</div>} */}
|
||||
{/* </div> */}
|
||||
{typeInfo.err &&
|
||||
<div>
|
||||
{typeInfo.err.message.split('\n')[1]}
|
||||
</div>}
|
||||
<Input
|
||||
placeholder="<c>"
|
||||
text=""
|
||||
|
|
|
|||
|
|
@ -3,16 +3,14 @@ import { memo, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|||
import { trie } from "dope2";
|
||||
|
||||
import { EnvContext } from "../../context/EnvContext";
|
||||
// import type { Environment, ResolvedType } from "./eval";
|
||||
import "./InputBlock.css";
|
||||
import { Type } from "../other/Type";
|
||||
import type { ExprBlockState, State2Props } from "./ExprBlock";
|
||||
// import { attemptParseLiteral } from "./eval";
|
||||
import { Input } from "../other/Input";
|
||||
import { CallContext } from "../../context/CallContext";
|
||||
import { getActions } from "../app/actions";
|
||||
import { GlobalContext } from "../../context/GlobalContext";
|
||||
import { inferTypeInput } from "../../eval/infer_type";
|
||||
import { inferType, inferTypeInput, type Environment, type Type } from "../../eval/infer_type";
|
||||
import { Type as TypeBlock } from "../other/Type";
|
||||
|
||||
interface Literal {
|
||||
kind: "literal";
|
||||
|
|
@ -21,47 +19,60 @@ interface Literal {
|
|||
interface Name {
|
||||
kind: "name";
|
||||
}
|
||||
interface Text {
|
||||
kind: "text";
|
||||
interface Gibberish {
|
||||
kind: "gibberish";
|
||||
}
|
||||
export type InputValueType = Literal | Name | Text;
|
||||
export type InputValueType = Literal | Name | Gibberish;
|
||||
|
||||
export interface InputBlockState {
|
||||
kind: "input";
|
||||
text: string;
|
||||
value: InputValueType;
|
||||
focus: boolean
|
||||
focus?: boolean;
|
||||
}
|
||||
|
||||
// export type SuggestionType = ["literal"|"name", string, ResolvedType];
|
||||
// export type PrioritizedSuggestionType = [number, ...SuggestionType];
|
||||
export type PrioritizedSuggestionType = [number, Type, InputBlockState];
|
||||
|
||||
export interface InputBlockProps extends State2Props<InputBlockState,ExprBlockState> {
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
// const computeSuggestions = (
|
||||
// text: string,
|
||||
// env: Environment,
|
||||
// score: InputBlockProps['score'],
|
||||
// ): PrioritizedSuggestionType[] => {
|
||||
// const literals = attemptParseLiteral(text, env);
|
||||
// const ls: SuggestionType[] = [
|
||||
// // literals
|
||||
// ... literals.map((resolved) => ["literal", text, resolved]),
|
||||
const attemptLiterals = [
|
||||
["Double", text => (text !== '') && !Number.isNaN(Number(text))],
|
||||
["Int" , text => /^-?[0-9]+$/.test(text)]
|
||||
] as [string, (text: string) => boolean][];
|
||||
|
||||
// // names
|
||||
// ... trie.suggest(env.names)(text)(Infinity)
|
||||
// .map(([name, resolved]) => ["name", name, resolved]),
|
||||
// ]
|
||||
// // return []; // <-- uncomment to disable suggestions (useful for debugging)
|
||||
// return ls
|
||||
// .map((suggestion: SuggestionType) =>
|
||||
// [score(suggestion[2]), ...suggestion] as PrioritizedSuggestionType)
|
||||
// .sort(([priorityA], [priorityB]) => priorityB - priorityA)
|
||||
// }
|
||||
const computeSuggestions = (
|
||||
text: string,
|
||||
env: Environment,
|
||||
score: InputBlockProps['score'],
|
||||
): PrioritizedSuggestionType[] => {
|
||||
const ls = [
|
||||
...attemptLiterals
|
||||
.filter(([_, test]) => test(text))
|
||||
.map(([typename]) => ({
|
||||
kind: "input",
|
||||
text,
|
||||
value: {
|
||||
kind: "literal",
|
||||
type: typename,
|
||||
},
|
||||
})),
|
||||
...trie.suggest(env.names)(text)(Infinity)
|
||||
.map(([name]) => ({
|
||||
kind: "input",
|
||||
text: name,
|
||||
value: {
|
||||
kind: "name",
|
||||
},
|
||||
})),
|
||||
];
|
||||
// return []; // <-- uncomment to disable suggestions (useful for debugging)
|
||||
return ls.map((state) => [score(state), inferType(state, env).type, state] as PrioritizedSuggestionType)
|
||||
.sort(([a],[b]) => b-a);
|
||||
}
|
||||
|
||||
export function InputBlock({ state, setState, /*score,*/ onCancel }: InputBlockProps) {
|
||||
export function InputBlock({ state, setState, score, onCancel }: InputBlockProps) {
|
||||
const {text, focus} = state;
|
||||
const globalContext = useContext(GlobalContext);
|
||||
const env = useContext(EnvContext);
|
||||
|
|
@ -70,8 +81,7 @@ export function InputBlock({ state, setState, /*score,*/ onCancel }: InputBlockP
|
|||
const [i, setI] = useState(0); // selected suggestion idx
|
||||
|
||||
const singleSuggestion = trie.growPrefix(env.names)(text);
|
||||
// const suggestions = useMemo(() => computeSuggestions(text, env, score), [text, score, env]);
|
||||
const suggestions = useMemo(() => [], []);
|
||||
const suggestions = useMemo(() => computeSuggestions(text, env, score), [text, score, env]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -96,21 +106,8 @@ export function InputBlock({ state, setState, /*score,*/ onCancel }: InputBlockP
|
|||
}
|
||||
|
||||
const onSelectSuggestion = () => {
|
||||
// const [_priority, kind, name, dynamic] = suggestions[i];
|
||||
// if (kind === "literal") {
|
||||
// setState(state => ({
|
||||
// ...state,
|
||||
// text: name,
|
||||
// value: {kind, type: prettyT(getType(dynamic))},
|
||||
// }));
|
||||
// }
|
||||
// else {
|
||||
// setState(state => ({
|
||||
// ...state,
|
||||
// text: name,
|
||||
// value: {kind},
|
||||
// }))
|
||||
// }
|
||||
const [_priority, _type, inputState] = suggestions[i];
|
||||
setState(_ => inputState);
|
||||
};
|
||||
|
||||
const extraHandlers = {
|
||||
|
|
@ -154,7 +151,7 @@ export function InputBlock({ state, setState, /*score,*/ onCancel }: InputBlockP
|
|||
i={i} setI={setI} />
|
||||
</span>
|
||||
</Input>
|
||||
::<Type type={typeInfo.type} />
|
||||
::<TypeBlock type={typeInfo.type} />
|
||||
</>
|
||||
}
|
||||
|
||||
|
|
@ -176,10 +173,10 @@ interface SuggestionProps {
|
|||
j: number;
|
||||
onSelect: any;
|
||||
highlighted: boolean;
|
||||
// suggestion: PrioritizedSuggestionType;
|
||||
suggestion: PrioritizedSuggestionType;
|
||||
}
|
||||
|
||||
function Suggestion({ setI, j, onSelect, highlighted, /*suggestion: [priority, kind, text, resolved]*/ }: SuggestionProps) {
|
||||
function Suggestion({ setI, j, onSelect, highlighted, suggestion: [priority, type, {text, value: {kind} }] }: SuggestionProps) {
|
||||
const onMouseEnter = j => () => {
|
||||
setI(j);
|
||||
};
|
||||
|
|
@ -192,7 +189,7 @@ function Suggestion({ setI, j, onSelect, highlighted, /*suggestion: [priority, k
|
|||
className={(highlighted ? " selected" : "")}
|
||||
onMouseEnter={onMouseEnter(j)}
|
||||
onMouseDown={onMouseDown(j)}>
|
||||
{/* ({priority}) ({kind}) {text} :: <Type type={resolved.t} /> */}
|
||||
({priority}) ({kind}) {text} :: <TypeBlock type={type} />
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,10 +71,7 @@ export function LambdaBlock({state, setState, score}: LambdaBlockProps) {
|
|||
state={state.expr}
|
||||
setState={setExpr}
|
||||
onCancel={() => setState(state => state.expr)}
|
||||
score={(s) => {
|
||||
// console.log('suggestionPriority of lambdaInner... just passing through');
|
||||
return score(s);
|
||||
}}
|
||||
score={suggestion => score({...state, expr: suggestion})}
|
||||
/>
|
||||
</EnvContext>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { useContext } from "react";
|
|||
|
||||
import { ExprBlock, type ExprBlockState } from "./ExprBlock";
|
||||
import { EnvContext } from "../../context/EnvContext";
|
||||
// import { evalExprBlock, makeInnerEnv, scoreResolved, type ResolvedType } from "./eval";
|
||||
import { type State2Props } from "./ExprBlock";
|
||||
import { GlobalContext } from "../../context/GlobalContext";
|
||||
|
||||
|
|
@ -40,16 +39,7 @@ function DeclColumns({state, setState, score}) {
|
|||
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
||||
const setValue = callback => setState(state => ({...state, value: callback(state.value)}));
|
||||
|
||||
// const valueSuggestionPriority = (suggestion: ResolvedType) => {
|
||||
// const innerEnv = makeInnerEnv(env, name, suggestion);
|
||||
// const [resolved] = evalExprBlock(inner, innerEnv);
|
||||
// return scoreResolved(resolved, score);
|
||||
// };
|
||||
|
||||
// const [valueResolved] = evalExprBlock(value, env);
|
||||
// const innerEnv = makeInnerEnv(env, name, valueResolved);
|
||||
|
||||
const {paramType, innerEnv} = inferTypeLet(state, env);
|
||||
const {value: valueTypeInfo, innerEnv} = inferTypeLet(state, env);
|
||||
|
||||
return <>
|
||||
<span className="keyword column">let </span>
|
||||
|
|
@ -63,14 +53,14 @@ function DeclColumns({state, setState, score}) {
|
|||
onTextChange={name => setState(state => ({...state, name}))}
|
||||
extraHandlers={{}}
|
||||
/>
|
||||
:: <Type type={paramType} />
|
||||
:: <Type type={valueTypeInfo.type} />
|
||||
</span>
|
||||
<span className="keyword column"> = </span>
|
||||
<span className="column">
|
||||
<ExprBlock
|
||||
state={state.value}
|
||||
setState={setValue}
|
||||
score={() => 0}
|
||||
score={suggestion => score({ ...state, value: suggestion })}
|
||||
onCancel={() => setState(state => state.inner)} // keep inner
|
||||
/>
|
||||
</span>
|
||||
|
|
@ -80,7 +70,7 @@ function DeclColumns({state, setState, score}) {
|
|||
<DeclColumns
|
||||
state={state.inner}
|
||||
setState={setInner}
|
||||
score={score}
|
||||
score={suggestion => score({ ...state, inner: suggestion })}
|
||||
/>
|
||||
</EnvContext>
|
||||
}
|
||||
|
|
@ -93,14 +83,14 @@ function InnerMost({state, setState, score}) {
|
|||
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
||||
// const [valueResolved] = evalExprBlock(state.value, env);
|
||||
// const innerEnv = makeInnerEnv(env, state.name, valueResolved);
|
||||
const {paramType, innerEnv} = inferTypeLet(state, env);
|
||||
const {innerEnv} = inferTypeLet(state, env);
|
||||
const onCancel = () => setState(state => state.value);
|
||||
if (state.inner.kind === "let" && globalContext?.syntacticSugar) {
|
||||
return <EnvContext value={innerEnv}>
|
||||
<InnerMost
|
||||
state={state.inner}
|
||||
setState={setInner}
|
||||
score={score}
|
||||
score={suggestion => score({ ...state, inner: suggestion })}
|
||||
/>
|
||||
</EnvContext>;
|
||||
}
|
||||
|
|
@ -109,7 +99,7 @@ function InnerMost({state, setState, score}) {
|
|||
<ExprBlock
|
||||
state={state.inner}
|
||||
setState={setInner}
|
||||
score={score}
|
||||
score={suggestion => score({ ...state, inner: suggestion })}
|
||||
onCancel={onCancel} // keep value
|
||||
/>
|
||||
</EnvContext>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue