infer all types once at the root level, and pass the result down deeply
This commit is contained in:
parent
b2584a2495
commit
d000839878
6 changed files with 75 additions and 80 deletions
|
|
@ -1,11 +1,10 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { extendedEnv } from '../../context/EnvContext';
|
import { extendedEnv } from '../../context/EnvContext';
|
||||||
import { GlobalContext } from '../../context/GlobalContext';
|
import { GlobalContext } from '../../context/GlobalContext';
|
||||||
import { inferType, scoreTypeInfo } from '../../eval/infer_type';
|
import { inferType, scoreTypeInfo } from '../../eval/infer_type';
|
||||||
import { ExprBlock, type ExprBlockState } from '../expr/ExprBlock';
|
import { ExprBlock, type ExprBlockState } from '../expr/ExprBlock';
|
||||||
import { actionShortcuts } from './actions';
|
import { actionShortcuts } from './actions';
|
||||||
import { biggerExample, emptySet, factorial, higherOrder, higherOrder2Params, inc, initialEditorState, lambda2Params, nonEmptyEditorState, pushBool, setOfListOfBool, tripleFunctionCallEditorState } from "./configurations";
|
import { biggerExample, emptySet, factorial, higherOrder, higherOrder2Params, inc, initialEditorState, lambda2Params, nonEmptyEditorState, pushBool, setOfListOfBool, tripleFunctionCallEditorState } from "./configurations";
|
||||||
// import { scoreResolved, type ResolvedType } from './eval';
|
|
||||||
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
|
||||||
|
|
@ -133,6 +132,11 @@ export function App() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentState = appState.history.at(-1)!;
|
||||||
|
|
||||||
|
// infer types for entire app state
|
||||||
|
const typeInfo = useMemo(() => inferType(currentState, extendedEnv), [currentState]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header>
|
<header>
|
||||||
|
|
@ -168,13 +172,14 @@ export function App() {
|
||||||
<main onKeyDown={onKeyDown}>
|
<main onKeyDown={onKeyDown}>
|
||||||
<GlobalContext value={{undo: onUndo, redo: onRedo, doHighlight, syntacticSugar}}>
|
<GlobalContext value={{undo: onUndo, redo: onRedo, doHighlight, syntacticSugar}}>
|
||||||
<ExprBlock
|
<ExprBlock
|
||||||
state={appState.history.at(-1)!}
|
state={currentState}
|
||||||
setState={pushHistory}
|
setState={pushHistory}
|
||||||
onCancel={() => {}}
|
onCancel={() => {}}
|
||||||
score={(state: ExprBlockState) => {
|
score={(state: ExprBlockState) => {
|
||||||
const typeInfo = inferType(state, extendedEnv);
|
const typeInfo = inferType(state, extendedEnv);
|
||||||
return scoreTypeInfo(typeInfo);
|
return scoreTypeInfo(typeInfo);
|
||||||
}}
|
}}
|
||||||
|
typeInfo={typeInfo}
|
||||||
/>
|
/>
|
||||||
</GlobalContext>
|
</GlobalContext>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
import { EnvContext } from "../../context/EnvContext";
|
|
||||||
import { ExprBlock, type ExprBlockState, type SetStateFn, type State2Props } from "./ExprBlock";
|
|
||||||
import { GlobalContext } from "../../context/GlobalContext";
|
|
||||||
|
|
||||||
import { getActions } from "../app/actions";
|
|
||||||
import "./CallBlock.css";
|
|
||||||
import { CallContext } from "../../context/CallContext";
|
import { CallContext } from "../../context/CallContext";
|
||||||
import { inferTypeCall, type Environment } from "../../eval/infer_type";
|
import { EnvContext } from "../../context/EnvContext";
|
||||||
|
import { GlobalContext } from "../../context/GlobalContext";
|
||||||
|
import { type Environment, type TypeInfoCall } from "../../eval/infer_type";
|
||||||
|
import { getActions } from "../app/actions";
|
||||||
import { Type } from "../other/Type";
|
import { Type } from "../other/Type";
|
||||||
|
import "./CallBlock.css";
|
||||||
|
import { ExprBlock, type ExprBlockState, type SetStateFn, type State2Props } from "./ExprBlock";
|
||||||
|
|
||||||
export interface CallBlockState {
|
export interface CallBlockState {
|
||||||
kind: "call";
|
kind: "call";
|
||||||
|
|
@ -19,9 +18,11 @@ export interface CallBlockState {
|
||||||
export interface CallBlockProps<
|
export interface CallBlockProps<
|
||||||
FnState=ExprBlockState,
|
FnState=ExprBlockState,
|
||||||
InputState=ExprBlockState,
|
InputState=ExprBlockState,
|
||||||
> extends State2Props<CallBlockState,ExprBlockState> {}
|
> extends State2Props<CallBlockState,ExprBlockState> {
|
||||||
|
typeInfo: TypeInfoCall;
|
||||||
|
}
|
||||||
|
|
||||||
function nestedFnProperties({state, setState, score}: CallBlockProps, env: Environment) {
|
function nestedFnProperties({state, setState, score, typeInfo}: CallBlockProps, env: Environment) {
|
||||||
const setFn = (callback: SetStateFn) => {
|
const setFn = (callback: SetStateFn) => {
|
||||||
setState(state => ({...state, fn: callback(state.fn)}));
|
setState(state => ({...state, fn: callback(state.fn)}));
|
||||||
};
|
};
|
||||||
|
|
@ -31,10 +32,10 @@ function nestedFnProperties({state, setState, score}: CallBlockProps, env: Envir
|
||||||
const scoreFn = (fnSuggestion: ExprBlockState) => {
|
const scoreFn = (fnSuggestion: ExprBlockState) => {
|
||||||
return score({ ...state, fn: fnSuggestion });
|
return score({ ...state, fn: fnSuggestion });
|
||||||
};
|
};
|
||||||
return {state: state.fn, setState: setFn, onCancel: onFnCancel, score: scoreFn};
|
return {state: state.fn, setState: setFn, onCancel: onFnCancel, score: scoreFn, typeInfo: typeInfo.fn};
|
||||||
}
|
}
|
||||||
|
|
||||||
function nestedInputProperties({state, setState, score}: CallBlockProps, env: Environment) {
|
function nestedInputProperties({state, setState, score, typeInfo}: CallBlockProps, env: Environment) {
|
||||||
const setInput = (callback: SetStateFn) => {
|
const setInput = (callback: SetStateFn) => {
|
||||||
setState(state => ({...state, input: callback(state.input)}));
|
setState(state => ({...state, input: callback(state.input)}));
|
||||||
};
|
};
|
||||||
|
|
@ -44,7 +45,7 @@ function nestedInputProperties({state, setState, score}: CallBlockProps, env: En
|
||||||
const scoreInput = (inputSuggestion: ExprBlockState) => {
|
const scoreInput = (inputSuggestion: ExprBlockState) => {
|
||||||
return score({ ...state, input: inputSuggestion });
|
return score({ ...state, input: inputSuggestion });
|
||||||
};
|
};
|
||||||
return {state: state.input, setState: setInput, onCancel: onInputCancel, score: scoreInput};
|
return {state: state.input, setState: setInput, onCancel: onInputCancel, score: scoreInput, typeInfo: typeInfo.input};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CallBlock(props: CallBlockProps) {
|
export function CallBlock(props: CallBlockProps) {
|
||||||
|
|
@ -53,7 +54,6 @@ export function CallBlock(props: CallBlockProps) {
|
||||||
const addParam = getActions(globalContext, props.setState).c;
|
const addParam = getActions(globalContext, props.setState).c;
|
||||||
// const [resolved] = evalExprBlock(props.state, env);
|
// const [resolved] = evalExprBlock(props.state, env);
|
||||||
// return <span className={"functionBlock" + ((resolved.kind === "error") ? " unifyError" : "")}>
|
// return <span className={"functionBlock" + ((resolved.kind === "error") ? " unifyError" : "")}>
|
||||||
const typeInfo = inferTypeCall(props.state, env);
|
|
||||||
return <span className={"functionBlock"}>
|
return <span className={"functionBlock"}>
|
||||||
<CallContext value={{addParam}}>
|
<CallContext value={{addParam}}>
|
||||||
<FunctionHeader {...props} addParam={addParam} />
|
<FunctionHeader {...props} addParam={addParam} />
|
||||||
|
|
@ -67,7 +67,7 @@ export function CallBlock(props: CallBlockProps) {
|
||||||
{/* { (resolved.kind === "error") && resolved.e.toString()
|
{/* { (resolved.kind === "error") && resolved.e.toString()
|
||||||
|| (resolved.kind === "value") && <Value dynamic={resolved} />
|
|| (resolved.kind === "value") && <Value dynamic={resolved} />
|
||||||
|| "unknown" } */}
|
|| "unknown" } */}
|
||||||
:: <Type type={typeInfo.type} />
|
:: <Type type={props.typeInfo.type} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CallContext>
|
</CallContext>
|
||||||
|
|
@ -92,22 +92,21 @@ function FunctionHeader(props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function InputParams({ ...rest }) {
|
function InputParams(props) {
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
const typeInfo = inferTypeCall(rest.state, env);
|
const inputEnv = props.typeInfo.fn.newEnv;
|
||||||
const inputEnv = typeInfo.fn.newEnv;
|
const isOffending = props.typeInfo.err;
|
||||||
const isOffending = typeInfo.err;
|
|
||||||
return <div className={"inputParam" + (isOffending ? " offending" : "")}>
|
return <div className={"inputParam" + (isOffending ? " offending" : "")}>
|
||||||
{rest.state.fn.kind === "call"
|
{props.state.fn.kind === "call"
|
||||||
&& globalContext?.syntacticSugar
|
&& globalContext?.syntacticSugar
|
||||||
&& <InputParams
|
&& <InputParams
|
||||||
{...nestedFnProperties(rest as CallBlockProps, env)}
|
{...nestedFnProperties(props as CallBlockProps, env)}
|
||||||
/>}
|
/>}
|
||||||
{/* Our own input param */}
|
{/* Our own input param */}
|
||||||
<EnvContext value={inputEnv}>
|
<EnvContext value={inputEnv}>
|
||||||
<ExprBlock
|
<ExprBlock
|
||||||
{...nestedInputProperties(rest as CallBlockProps, env)}
|
{...nestedInputProperties(props as CallBlockProps, env)}
|
||||||
/>
|
/>
|
||||||
</EnvContext>
|
</EnvContext>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
import { CallBlock, type CallBlockProps, type CallBlockState } from "./CallBlock";
|
|
||||||
import { EnvContext } from "../../context/EnvContext";
|
import { EnvContext } from "../../context/EnvContext";
|
||||||
import { GlobalContext } from "../../context/GlobalContext";
|
import { GlobalContext } from "../../context/GlobalContext";
|
||||||
|
import { type TypeInfo } from "../../eval/infer_type";
|
||||||
|
import { getActions } from "../app/actions";
|
||||||
|
import { Input } from "../other/Input";
|
||||||
|
import { CallBlock, type CallBlockProps, type CallBlockState } from "./CallBlock";
|
||||||
import { InputBlock, type InputBlockProps, type InputBlockState } from "./InputBlock";
|
import { InputBlock, type InputBlockProps, type InputBlockState } from "./InputBlock";
|
||||||
import { LambdaBlock, type LambdaBlockProps, type LambdaBlockState } from "./LambdaBlock";
|
import { LambdaBlock, type LambdaBlockProps, type LambdaBlockState } from "./LambdaBlock";
|
||||||
import { LetInBlock, type LetInBlockProps, type LetInBlockState } from "./LetInBlock";
|
import { LetInBlock, type LetInBlockProps, type LetInBlockState } from "./LetInBlock";
|
||||||
// import { evalExprBlock, type ResolvedType } from "./eval";
|
|
||||||
|
|
||||||
import "./ExprBlock.css";
|
import "./ExprBlock.css";
|
||||||
import { Input } from "../other/Input";
|
|
||||||
import { getActions } from "../app/actions";
|
|
||||||
import { inferType, type Type } from "../../eval/infer_type";
|
|
||||||
|
|
||||||
export type ExprBlockState =
|
export type ExprBlockState =
|
||||||
InputBlockState
|
InputBlockState
|
||||||
|
|
@ -22,9 +21,15 @@ export type ExprBlockState =
|
||||||
export type SetStateFn<InType = ExprBlockState, OutType = InType> = (state: InType) => OutType;
|
export type SetStateFn<InType = ExprBlockState, OutType = InType> = (state: InType) => OutType;
|
||||||
|
|
||||||
export interface State2Props<InType, OutType = InType> {
|
export interface State2Props<InType, OutType = InType> {
|
||||||
|
// Every block gets passed its part of the global app state, and a functino to update that part of the state
|
||||||
state: InType;
|
state: InType;
|
||||||
setState: (callback: SetStateFn<InType, OutType>) => void;
|
setState: (callback: SetStateFn<InType, OutType>) => void;
|
||||||
|
|
||||||
|
// To compute the priority of an input suggestion. The root ExprBlock's score function counts the number of errors and subtracts points for every error. Every block passes to its children ExprBlock's a wrapped score-function that creates an app-state with only the child altered, computing a score for that app-state.
|
||||||
score: (suggestion: ExprBlockState) => number;
|
score: (suggestion: ExprBlockState) => number;
|
||||||
|
|
||||||
|
// All types are inferred once after every App-state change, and passed deeply to all descendants.
|
||||||
|
typeInfo: TypeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExprBlockProps extends State2Props<ExprBlockState> {
|
interface ExprBlockProps extends State2Props<ExprBlockState> {
|
||||||
|
|
@ -42,19 +47,15 @@ export function ExprBlock(props: ExprBlockProps) {
|
||||||
lambda: () => <LambdaBlock {...props as LambdaBlockProps} />,
|
lambda: () => <LambdaBlock {...props as LambdaBlockProps} />,
|
||||||
};
|
};
|
||||||
|
|
||||||
// const [resolved] = evalExprBlock(props.state, env);
|
|
||||||
// const typeInfo = inferType(props.state, env);
|
|
||||||
const actions = getActions(globalContext, props.setState);
|
const actions = getActions(globalContext, props.setState);
|
||||||
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
||||||
[shortcut, (e) => { e.preventDefault(); action(); }]))
|
[shortcut, (e) => { e.preventDefault(); action(); }]))
|
||||||
|
|
||||||
const typeInfo = inferType(props.state, env);
|
return <span className={"editor" + (props.typeInfo.err ? " error" : "")}>
|
||||||
|
|
||||||
return <span className={"editor" + (typeInfo.err ? " error" : "")}>
|
|
||||||
{renderBlock[props.state.kind]()}
|
{renderBlock[props.state.kind]()}
|
||||||
{typeInfo.err &&
|
{props.typeInfo.err &&
|
||||||
<div>
|
<div>
|
||||||
{typeInfo.err.message.split('\n')[1]}
|
{props.typeInfo.err.message.split('\n')[1]}
|
||||||
</div>}
|
</div>}
|
||||||
<Input
|
<Input
|
||||||
placeholder="<c>"
|
placeholder="<c>"
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,16 @@ import { memo, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
|
||||||
import { trie } from "dope2";
|
import { trie } from "dope2";
|
||||||
|
|
||||||
import { EnvContext } from "../../context/EnvContext";
|
|
||||||
import "./InputBlock.css";
|
|
||||||
import type { ExprBlockState, State2Props } from "./ExprBlock";
|
|
||||||
import { Input } from "../other/Input";
|
|
||||||
import { CallContext } from "../../context/CallContext";
|
import { CallContext } from "../../context/CallContext";
|
||||||
import { getActions } from "../app/actions";
|
import { EnvContext } from "../../context/EnvContext";
|
||||||
import { GlobalContext } from "../../context/GlobalContext";
|
import { GlobalContext } from "../../context/GlobalContext";
|
||||||
import { inferType, inferTypeInput, type Environment, type Type } from "../../eval/infer_type";
|
import { inferTypeInput, type Environment, type Type, type TypeInfoInput } from "../../eval/infer_type";
|
||||||
|
import { getActions } from "../app/actions";
|
||||||
|
import { Input } from "../other/Input";
|
||||||
import { Type as TypeBlock } from "../other/Type";
|
import { Type as TypeBlock } from "../other/Type";
|
||||||
|
import type { ExprBlockState, State2Props } from "./ExprBlock";
|
||||||
|
|
||||||
|
import "./InputBlock.css";
|
||||||
|
|
||||||
interface Literal {
|
interface Literal {
|
||||||
kind: "literal";
|
kind: "literal";
|
||||||
|
|
@ -35,6 +36,7 @@ export type PrioritizedSuggestionType = [number, Type, InputBlockState];
|
||||||
|
|
||||||
export interface InputBlockProps extends State2Props<InputBlockState,ExprBlockState> {
|
export interface InputBlockProps extends State2Props<InputBlockState,ExprBlockState> {
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
|
typeInfo: TypeInfoInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attemptLiterals = [
|
const attemptLiterals = [
|
||||||
|
|
@ -68,11 +70,11 @@ const computeSuggestions = (
|
||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
// return []; // <-- uncomment to disable suggestions (useful for debugging)
|
// return []; // <-- uncomment to disable suggestions (useful for debugging)
|
||||||
return ls.map((state) => [score(state), inferType(state, env).type, state] as PrioritizedSuggestionType)
|
return ls.map((state) => [score(state), inferTypeInput(state, env).type, state] as PrioritizedSuggestionType)
|
||||||
.sort(([a],[b]) => b-a);
|
.sort(([a],[b]) => b-a);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InputBlock({ state, setState, score, onCancel }: InputBlockProps) {
|
export function InputBlock({ state, setState, score, onCancel, typeInfo }: InputBlockProps) {
|
||||||
const {text, focus} = state;
|
const {text, focus} = state;
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
|
|
@ -133,8 +135,6 @@ export function InputBlock({ state, setState, score, onCancel }: InputBlockProps
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const typeInfo = inferTypeInput(state, env);
|
|
||||||
|
|
||||||
return <><Input
|
return <><Input
|
||||||
placeholder="<name or literal>"
|
placeholder="<name or literal>"
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
// import { eqType, getSymbol, reduceUnification } from "dope2";
|
|
||||||
|
|
||||||
import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock";
|
|
||||||
import { EnvContext } from "../../context/EnvContext";
|
import { EnvContext } from "../../context/EnvContext";
|
||||||
// import { evalExprBlock, evalLambdaBlock, makeInnerEnv, makeTypeVar } from "./eval";
|
import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock";
|
||||||
|
|
||||||
import "./LambdaBlock.css";
|
import { type TypeInfoLambda } from "../../eval/infer_type";
|
||||||
import { Type } from "../other/Type";
|
|
||||||
import { Input } from "../other/Input";
|
import { Input } from "../other/Input";
|
||||||
import { inferTypeLambda } from "../../eval/infer_type";
|
import { Type } from "../other/Type";
|
||||||
|
import "./LambdaBlock.css";
|
||||||
|
|
||||||
export interface LambdaBlockState {
|
export interface LambdaBlockState {
|
||||||
kind: "lambda";
|
kind: "lambda";
|
||||||
|
|
@ -22,10 +19,11 @@ export interface LambdaBlockProps<
|
||||||
FnState=ExprBlockState,
|
FnState=ExprBlockState,
|
||||||
InputState=ExprBlockState,
|
InputState=ExprBlockState,
|
||||||
> extends State2Props<LambdaBlockState,ExprBlockState> {
|
> extends State2Props<LambdaBlockState,ExprBlockState> {
|
||||||
|
typeInfo: TypeInfoLambda;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function LambdaBlock({state, setState, score}: LambdaBlockProps) {
|
export function LambdaBlock({state, setState, score, typeInfo}: LambdaBlockProps) {
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
|
|
||||||
const setParamName = paramName => setState(state => ({
|
const setParamName = paramName => setState(state => ({
|
||||||
|
|
@ -37,14 +35,6 @@ export function LambdaBlock({state, setState, score}: LambdaBlockProps) {
|
||||||
expr: callback(state.expr),
|
expr: callback(state.expr),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const {paramType, innerEnv} = inferTypeLambda(state, env);
|
|
||||||
|
|
||||||
// const [lambdaResolved, _, innerEnv] = evalLambdaBlock(state.paramName, state.expr, env);
|
|
||||||
|
|
||||||
// const inferredParamType = lambdaResolved.t.params[0](lambdaResolved.t);
|
|
||||||
|
|
||||||
// const innerEnv = env; // todo: change this
|
|
||||||
|
|
||||||
return <span className="lambdaBlock">
|
return <span className="lambdaBlock">
|
||||||
<span className="keyword">λ</span>
|
<span className="keyword">λ</span>
|
||||||
|
|
||||||
|
|
@ -60,18 +50,19 @@ export function LambdaBlock({state, setState, score}: LambdaBlockProps) {
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<div className="typeSignature">
|
<div className="typeSignature">
|
||||||
:: <Type type={paramType} />
|
:: <Type type={typeInfo.paramType} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span className="keyword">:</span>
|
<span className="keyword">:</span>
|
||||||
|
|
||||||
<div className="lambdaInner">
|
<div className="lambdaInner">
|
||||||
<EnvContext value={innerEnv}>
|
<EnvContext value={typeInfo.innerEnv}>
|
||||||
<ExprBlock
|
<ExprBlock
|
||||||
state={state.expr}
|
state={state.expr}
|
||||||
setState={setExpr}
|
setState={setExpr}
|
||||||
onCancel={() => setState(state => state.expr)}
|
onCancel={() => setState(state => state.expr)}
|
||||||
score={suggestion => score({...state, expr: suggestion})}
|
score={suggestion => score({...state, expr: suggestion})}
|
||||||
|
typeInfo={typeInfo.inner}
|
||||||
/>
|
/>
|
||||||
</EnvContext>
|
</EnvContext>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
import { ExprBlock, type ExprBlockState } from "./ExprBlock";
|
|
||||||
import { EnvContext } from "../../context/EnvContext";
|
import { EnvContext } from "../../context/EnvContext";
|
||||||
import { type State2Props } from "./ExprBlock";
|
|
||||||
import { GlobalContext } from "../../context/GlobalContext";
|
import { GlobalContext } from "../../context/GlobalContext";
|
||||||
|
import { type TypeInfoLet } from "../../eval/infer_type";
|
||||||
|
import { Input } from "../other/Input";
|
||||||
|
import { Type } from "../other/Type";
|
||||||
|
import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock";
|
||||||
|
|
||||||
import "./LetInBlock.css";
|
import "./LetInBlock.css";
|
||||||
import { Input } from "../other/Input";
|
|
||||||
import { inferTypeLet } from "../../eval/infer_type";
|
|
||||||
import { Type } from "../other/Type";
|
|
||||||
|
|
||||||
export interface LetInBlockState {
|
export interface LetInBlockState {
|
||||||
kind: "let";
|
kind: "let";
|
||||||
|
|
@ -19,6 +18,7 @@ export interface LetInBlockState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LetInBlockProps extends State2Props<LetInBlockState,ExprBlockState> {
|
export interface LetInBlockProps extends State2Props<LetInBlockState,ExprBlockState> {
|
||||||
|
typeInfo: TypeInfoLet;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LetInBlock(props: LetInBlockProps) {
|
export function LetInBlock(props: LetInBlockProps) {
|
||||||
|
|
@ -32,15 +32,13 @@ export function LetInBlock(props: LetInBlockProps) {
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
function DeclColumns({state, setState, score}) {
|
function DeclColumns({state, setState, score, typeInfo}) {
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
|
|
||||||
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
||||||
const setValue = callback => setState(state => ({...state, value: callback(state.value)}));
|
const setValue = callback => setState(state => ({...state, value: callback(state.value)}));
|
||||||
|
|
||||||
const {value: valueTypeInfo, innerEnv} = inferTypeLet(state, env);
|
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<span className="keyword column">let </span>
|
<span className="keyword column">let </span>
|
||||||
<span className="column rightAlign">
|
<span className="column rightAlign">
|
||||||
|
|
@ -53,7 +51,7 @@ function DeclColumns({state, setState, score}) {
|
||||||
onTextChange={name => setState(state => ({...state, name}))}
|
onTextChange={name => setState(state => ({...state, name}))}
|
||||||
extraHandlers={{}}
|
extraHandlers={{}}
|
||||||
/>
|
/>
|
||||||
:: <Type type={valueTypeInfo.type} />
|
:: <Type type={typeInfo.value.type} />
|
||||||
</span>
|
</span>
|
||||||
<span className="keyword column"> = </span>
|
<span className="keyword column"> = </span>
|
||||||
<span className="column">
|
<span className="column">
|
||||||
|
|
@ -62,45 +60,46 @@ function DeclColumns({state, setState, score}) {
|
||||||
setState={setValue}
|
setState={setValue}
|
||||||
score={suggestion => score({ ...state, value: suggestion })}
|
score={suggestion => score({ ...state, value: suggestion })}
|
||||||
onCancel={() => setState(state => state.inner)} // keep inner
|
onCancel={() => setState(state => state.inner)} // keep inner
|
||||||
|
typeInfo={typeInfo.value}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
{state.inner.kind === "let" &&
|
{state.inner.kind === "let" &&
|
||||||
globalContext?.syntacticSugar &&
|
globalContext?.syntacticSugar &&
|
||||||
<EnvContext value={innerEnv}>
|
<EnvContext value={typeInfo.innerEnv}>
|
||||||
<DeclColumns
|
<DeclColumns
|
||||||
state={state.inner}
|
state={state.inner}
|
||||||
setState={setInner}
|
setState={setInner}
|
||||||
score={suggestion => score({ ...state, inner: suggestion })}
|
score={suggestion => score({ ...state, inner: suggestion })}
|
||||||
|
typeInfo={typeInfo.inner}
|
||||||
/>
|
/>
|
||||||
</EnvContext>
|
</EnvContext>
|
||||||
}
|
}
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function InnerMost({state, setState, score}) {
|
function InnerMost({state, setState, score, typeInfo}) {
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
||||||
// const [valueResolved] = evalExprBlock(state.value, env);
|
|
||||||
// const innerEnv = makeInnerEnv(env, state.name, valueResolved);
|
|
||||||
const {innerEnv} = inferTypeLet(state, env);
|
|
||||||
const onCancel = () => setState(state => state.value);
|
const onCancel = () => setState(state => state.value);
|
||||||
if (state.inner.kind === "let" && globalContext?.syntacticSugar) {
|
if (state.inner.kind === "let" && globalContext?.syntacticSugar) {
|
||||||
return <EnvContext value={innerEnv}>
|
return <EnvContext value={typeInfo.innerEnv}>
|
||||||
<InnerMost
|
<InnerMost
|
||||||
state={state.inner}
|
state={state.inner}
|
||||||
setState={setInner}
|
setState={setInner}
|
||||||
score={suggestion => score({ ...state, inner: suggestion })}
|
score={suggestion => score({ ...state, inner: suggestion })}
|
||||||
|
typeInfo={typeInfo.inner}
|
||||||
/>
|
/>
|
||||||
</EnvContext>;
|
</EnvContext>;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return <EnvContext value={innerEnv}>
|
return <EnvContext value={typeInfo.innerEnv}>
|
||||||
<ExprBlock
|
<ExprBlock
|
||||||
state={state.inner}
|
state={state.inner}
|
||||||
setState={setInner}
|
setState={setInner}
|
||||||
score={suggestion => score({ ...state, inner: suggestion })}
|
score={suggestion => score({ ...state, inner: suggestion })}
|
||||||
onCancel={onCancel} // keep value
|
onCancel={onCancel} // keep value
|
||||||
|
typeInfo={typeInfo.inner}
|
||||||
/>
|
/>
|
||||||
</EnvContext>
|
</EnvContext>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue