rename Editor -> ExprBlock

This commit is contained in:
Joeri Exelmans 2025-05-18 11:10:25 +02:00
parent fe83532261
commit 93f665ba8f
9 changed files with 55 additions and 56 deletions

View file

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import './App.css'; import './App.css';
import { GlobalContext } from './GlobalContext'; import { GlobalContext } from './GlobalContext';
import { Editor, type EditorState } from './Editor'; import { ExprBlock, type ExprBlockState } from './ExprBlock';
import { extendedEnv } from './EnvContext'; import { extendedEnv } from './EnvContext';
import { biggerExample, initialEditorState, lambda2Params, nonEmptyEditorState, tripleFunctionCallEditorState } from "./configurations"; import { biggerExample, initialEditorState, lambda2Params, nonEmptyEditorState, tripleFunctionCallEditorState } from "./configurations";
import { evalEditorBlock } from "./eval"; import { evalEditorBlock } from "./eval";
@ -14,7 +14,7 @@ const commands: [string, string[], string][] = [
["lambda" , ['a' ], "λx: …" ], ["lambda" , ['a' ], "λx: …" ],
]; ];
const examples: [string, EditorState][] = [ const examples: [string, ExprBlockState][] = [
["empty editor", initialEditorState], ["empty editor", initialEditorState],
["push to list", nonEmptyEditorState], ["push to list", nonEmptyEditorState],
["function w/ 4 params", tripleFunctionCallEditorState], ["function w/ 4 params", tripleFunctionCallEditorState],
@ -23,8 +23,8 @@ const examples: [string, EditorState][] = [
]; ];
type AppState = { type AppState = {
history: EditorState[], history: ExprBlockState[],
future: EditorState[], future: ExprBlockState[],
} }
const defaultState = { const defaultState = {
@ -63,7 +63,7 @@ export function App() {
setAppState(_ => defaultState); setAppState(_ => defaultState);
} }
const pushHistory = (callback: (p: EditorState) => EditorState) => { const pushHistory = (callback: (p: ExprBlockState) => ExprBlockState) => {
setAppState(({history}) => { setAppState(({history}) => {
const newState = callback(history.at(-1)!); const newState = callback(history.at(-1)!);
return { return {
@ -162,7 +162,7 @@ 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}}>
<Editor <ExprBlock
state={appState.history.at(-1)!} state={appState.history.at(-1)!}
setState={pushHistory} setState={pushHistory}
onCancel={() => {}} onCancel={() => {}}

View file

@ -1,6 +1,6 @@
import { useContext } from "react"; import { useContext } from "react";
import { Editor, type EditorState, type SetStateFn, type State2Props } from "./Editor"; import { ExprBlock, type ExprBlockState, type SetStateFn, type State2Props } from "./ExprBlock";
import { EnvContext } from "./EnvContext"; import { EnvContext } from "./EnvContext";
import { evalCallBlock2, evalEditorBlock, scoreResolved, type ResolvedType } from "./eval"; import { evalCallBlock2, evalEditorBlock, scoreResolved, type ResolvedType } from "./eval";
import { GlobalContext } from "./GlobalContext"; import { GlobalContext } from "./GlobalContext";
@ -10,14 +10,14 @@ import "./CallBlock.css";
export interface CallBlockState { export interface CallBlockState {
kind: "call"; kind: "call";
fn: EditorState; fn: ExprBlockState;
input: EditorState; input: ExprBlockState;
} }
interface CallBlockProps< interface CallBlockProps<
FnState=EditorState, FnState=ExprBlockState,
InputState=EditorState, InputState=ExprBlockState,
> extends State2Props<CallBlockState,EditorState> {} > extends State2Props<CallBlockState,ExprBlockState> {}
function nestedFnProperties({state, setState, suggestionPriority}: CallBlockProps, env) { function nestedFnProperties({state, setState, suggestionPriority}: CallBlockProps, env) {
const setFn = (callback: SetStateFn) => { const setFn = (callback: SetStateFn) => {
@ -91,7 +91,7 @@ function FunctionHeader(props) {
// end of recursion - draw function name // end of recursion - draw function name
return <span className="functionName"> return <span className="functionName">
&nbsp;&#119891;&#119899;&nbsp; &nbsp;&#119891;&#119899;&nbsp;
<Editor {...nestedProperties} /> <ExprBlock {...nestedProperties} />
</span>; </span>;
} }
} }
@ -109,7 +109,7 @@ function InputParams({ depth, errorDepth, ...rest }) {
errorDepth={errorDepth} errorDepth={errorDepth}
/>} />}
{/* Our own input param */} {/* Our own input param */}
<Editor <ExprBlock
{...nestedInputProperties(rest as CallBlockProps, env)} {...nestedInputProperties(rest as CallBlockProps, env)}
/> />
</div>; </div>;

View file

@ -3,24 +3,25 @@ import { useContext, useEffect, useRef, useState } from "react";
import { getSymbol, getType, symbolFunction } from "dope2"; import { getSymbol, getType, symbolFunction } from "dope2";
import { CallBlock, type CallBlockState } from "./CallBlock"; import { CallBlock, type CallBlockState } from "./CallBlock";
import { InputBlock, type InputBlockState, type SuggestionType } from "./InputBlock";
import { Type } from "./Type";
import { evalEditorBlock, type ResolvedType } from "./eval";
import { GlobalContext } from "./GlobalContext";
import "./Editor.css";
import { EnvContext } from "./EnvContext"; import { EnvContext } from "./EnvContext";
import { GlobalContext } from "./GlobalContext";
import { InputBlock, type InputBlockState } from "./InputBlock";
import { LambdaBlock, type LambdaBlockState } from "./LambdaBlock"; import { LambdaBlock, type LambdaBlockState } from "./LambdaBlock";
import { LetInBlock, type LetInBlockState } from "./LetInBlock"; import { LetInBlock, type LetInBlockState } from "./LetInBlock";
import { Type } from "./Type";
import { initialEditorState } from "./configurations"; import { initialEditorState } from "./configurations";
import { evalEditorBlock, type ResolvedType } from "./eval";
import { focusNextElement, focusPrevElement } from "./util/dom_trickery"; import { focusNextElement, focusPrevElement } from "./util/dom_trickery";
export type EditorState = import "./ExprBlock.css";
export type ExprBlockState =
InputBlockState InputBlockState
| CallBlockState | CallBlockState
| LetInBlockState | LetInBlockState
| LambdaBlockState; | LambdaBlockState;
export type SetStateFn<InType = EditorState, 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> {
state: InType; state: InType;
@ -28,7 +29,7 @@ export interface State2Props<InType, OutType = InType> {
suggestionPriority: (suggestion: ResolvedType) => number; suggestionPriority: (suggestion: ResolvedType) => number;
} }
interface EditorProps extends State2Props<EditorState> { interface ExprBlockProps extends State2Props<ExprBlockState> {
onCancel: () => void; onCancel: () => void;
} }
@ -46,7 +47,7 @@ function getShortCommands(type) {
return 'Tab|.'; return 'Tab|.';
} }
function removeFocus(state: EditorState): EditorState { function removeFocus(state: ExprBlockState): ExprBlockState {
if (state.kind === "input") { if (state.kind === "input") {
return {...state, focus: false}; return {...state, focus: false};
} }
@ -59,7 +60,7 @@ function removeFocus(state: EditorState): EditorState {
return state; return state;
} }
export function Editor({state, setState, onCancel, suggestionPriority}: EditorProps) { export function ExprBlock({state, setState, onCancel, suggestionPriority}: ExprBlockProps) {
const env = useContext(EnvContext); const env = useContext(EnvContext);
const [needCommand, setNeedCommand] = useState(false); const [needCommand, setNeedCommand] = useState(false);
const commandInputRef = useRef<HTMLInputElement>(null); const commandInputRef = useRef<HTMLInputElement>(null);
@ -158,26 +159,26 @@ export function Editor({state, setState, onCancel, suggestionPriority}: EditorPr
case "input": case "input":
return <InputBlock return <InputBlock
state={state} state={state}
setState={setState as (callback:(p:InputBlockState)=>EditorState)=>void} setState={setState as (callback:(p:InputBlockState)=>ExprBlockState)=>void}
suggestionPriority={suggestionPriority} suggestionPriority={suggestionPriority}
onCancel={onCancel} onCancel={onCancel}
/>; />;
case "call": case "call":
return <CallBlock return <CallBlock
state={state} state={state}
setState={setState as (callback:(p:CallBlockState)=>EditorState)=>void} setState={setState as (callback:(p:CallBlockState)=>ExprBlockState)=>void}
suggestionPriority={suggestionPriority} suggestionPriority={suggestionPriority}
/>; />;
case "let": case "let":
return <LetInBlock return <LetInBlock
state={state} state={state}
setState={setState as (callback:(p:LetInBlockState)=>EditorState)=>void} setState={setState as (callback:(p:LetInBlockState)=>ExprBlockState)=>void}
suggestionPriority={suggestionPriority} suggestionPriority={suggestionPriority}
/>; />;
case "lambda": case "lambda":
return <LambdaBlock return <LambdaBlock
state={state} state={state}
setState={setState as (callback:(p:LambdaBlockState)=>EditorState)=>void} setState={setState as (callback:(p:LambdaBlockState)=>ExprBlockState)=>void}
suggestionPriority={suggestionPriority} suggestionPriority={suggestionPriority}
/>; />;
} }

View file

@ -6,7 +6,7 @@ import { EnvContext } from "./EnvContext";
import type { Dynamic, ResolvedType } from "./eval"; import type { Dynamic, ResolvedType } from "./eval";
import "./InputBlock.css"; import "./InputBlock.css";
import { Type } from "./Type"; import { Type } from "./Type";
import type { State2Props } from "./Editor"; import type { State2Props } from "./ExprBlock";
import { autoInputWidth, focusNextElement, focusPrevElement, setRightMostCaretPosition } from "./util/dom_trickery"; import { autoInputWidth, focusNextElement, focusPrevElement, setRightMostCaretPosition } from "./util/dom_trickery";
import { attemptParseLiteral } from "./eval"; import { attemptParseLiteral } from "./eval";

View file

@ -2,25 +2,23 @@ import { useContext, useEffect, useRef } from "react";
import { growEnv } from "dope2"; import { growEnv } from "dope2";
import { Editor, type EditorState, type State2Props } from "./Editor"; import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock";
import { EnvContext } from "./EnvContext"; import { EnvContext } from "./EnvContext";
import { evalEditorBlock, getUnusedTypeVar, type ResolvedType } from "./eval"; import { getUnusedTypeVar } from "./eval";
import { autoInputWidth } from "./util/dom_trickery"; import { autoInputWidth } from "./util/dom_trickery";
import "./LambdaBlock.css"; import "./LambdaBlock.css";
export interface LambdaBlockState { export interface LambdaBlockState {
kind: "lambda"; kind: "lambda";
paramName: string; paramName: string;
expr: EditorState; expr: ExprBlockState;
} }
interface LambdaBlockProps< interface LambdaBlockProps<
FnState=EditorState, FnState=ExprBlockState,
InputState=EditorState, InputState=ExprBlockState,
> extends State2Props<LambdaBlockState,EditorState> {} > extends State2Props<LambdaBlockState,ExprBlockState> {}
export function LambdaBlock({state, setState, suggestionPriority}: LambdaBlockProps) { export function LambdaBlock({state, setState, suggestionPriority}: LambdaBlockProps) {
@ -73,7 +71,7 @@ export function LambdaBlock({state, setState, suggestionPriority}: LambdaBlockPr
&nbsp; &nbsp;
<div className="lambdaInner"> <div className="lambdaInner">
<EnvContext value={innerEnv}> <EnvContext value={innerEnv}>
<Editor <ExprBlock
state={state.expr} state={state.expr}
setState={setExpr} setState={setExpr}
onCancel={() => setState(state => state.expr)} onCancel={() => setState(state => state.expr)}

View file

@ -1,9 +1,9 @@
import { useContext, useEffect, useRef } from "react"; import { useContext, useEffect, useRef } from "react";
import { Editor, type EditorState } from "./Editor"; import { ExprBlock, type ExprBlockState } from "./ExprBlock";
import { EnvContext } from "./EnvContext"; import { EnvContext } from "./EnvContext";
import { evalEditorBlock, makeInnerEnv, scoreResolved, type ResolvedType } from "./eval"; import { evalEditorBlock, makeInnerEnv, scoreResolved, type ResolvedType } from "./eval";
import { type State2Props } from "./Editor"; import { type State2Props } from "./ExprBlock";
import { autoInputWidth } from "./util/dom_trickery"; import { autoInputWidth } from "./util/dom_trickery";
import { GlobalContext } from "./GlobalContext"; import { GlobalContext } from "./GlobalContext";
@ -12,11 +12,11 @@ import "./LetInBlock.css";
export interface LetInBlockState { export interface LetInBlockState {
kind: "let"; kind: "let";
name: string; name: string;
value: EditorState; value: ExprBlockState;
inner: EditorState; inner: ExprBlockState;
} }
interface LetInBlockProps extends State2Props<LetInBlockState,EditorState> {} interface LetInBlockProps extends State2Props<LetInBlockState,ExprBlockState> {}
export function LetInBlock(props: LetInBlockProps) { export function LetInBlock(props: LetInBlockProps) {
return <span className="letIn"> return <span className="letIn">
@ -67,7 +67,7 @@ function DeclColumns({state: {name, value, inner}, setState, suggestionPriority}
</span> </span>
<span className="keyword column">&nbsp;=&nbsp;</span> <span className="keyword column">&nbsp;=&nbsp;</span>
<span className="column"> <span className="column">
<Editor <ExprBlock
state={value} state={value}
setState={setValue} setState={setValue}
suggestionPriority={valueSuggestionPriority} suggestionPriority={valueSuggestionPriority}
@ -105,7 +105,7 @@ function InnerMost({state, setState, suggestionPriority}) {
} }
else { else {
return <EnvContext value={innerEnv}> return <EnvContext value={innerEnv}>
<Editor <ExprBlock
state={state.inner} state={state.inner}
setState={setInner} setState={setInner}
suggestionPriority={suggestionPriority} suggestionPriority={suggestionPriority}

View file

@ -1,13 +1,13 @@
import type { EditorState } from "./Editor"; import type { ExprBlockState } from "./ExprBlock";
export const initialEditorState: EditorState = { export const initialEditorState: ExprBlockState = {
kind: "input", kind: "input",
text: "", text: "",
value: { kind: "text" }, value: { kind: "text" },
focus: true, focus: true,
}; };
export const nonEmptyEditorState: EditorState = { export const nonEmptyEditorState: ExprBlockState = {
kind: "call", kind: "call",
fn: { fn: {
kind: "call", kind: "call",
@ -32,7 +32,7 @@ export const nonEmptyEditorState: EditorState = {
}, },
}; };
export const tripleFunctionCallEditorState: EditorState = { export const tripleFunctionCallEditorState: ExprBlockState = {
kind: "call", kind: "call",
fn: { fn: {
kind: "call", kind: "call",
@ -75,7 +75,7 @@ export const tripleFunctionCallEditorState: EditorState = {
}, },
}; };
export const biggerExample: EditorState = { export const biggerExample: ExprBlockState = {
"kind": "let", "kind": "let",
"inner": { "inner": {
"kind": "let", "kind": "let",
@ -254,7 +254,7 @@ export const biggerExample: EditorState = {
} }
}; };
export const lambda2Params: EditorState = { export const lambda2Params: ExprBlockState = {
"kind": "let", "kind": "let",
"inner": { "inner": {
"kind": "input", "kind": "input",

View file

@ -1,6 +1,6 @@
import { assignFnSubstitutions, dict, Double, fnType, getSymbol, growEnv, Int, NotAFunctionError, prettyT, substitute, symbolFunction, trie, TYPE_VARS, UnifyError } from "dope2"; import { assignFnSubstitutions, dict, Double, fnType, getSymbol, growEnv, Int, NotAFunctionError, prettyT, substitute, symbolFunction, trie, TYPE_VARS, UnifyError } from "dope2";
import type { EditorState } from "./Editor"; import type { ExprBlockState } from "./ExprBlock";
import type { InputValueType, SuggestionType } from "./InputBlock"; import type { InputValueType, SuggestionType } from "./InputBlock";
interface Type { interface Type {
@ -39,7 +39,7 @@ export const entirelyUnknown = env => ({
// the value of every block is either known (Dynamic), an error, or unknown // the value of every block is either known (Dynamic), an error, or unknown
export type ResolvedType = Dynamic | DeepError | Unknown; export type ResolvedType = Dynamic | DeepError | Unknown;
export const evalEditorBlock = (s: EditorState, env): ResolvedType => { export const evalEditorBlock = (s: ExprBlockState, env): ResolvedType => {
if (s.kind === "input") { if (s.kind === "input") {
return evalInputBlock(s.text, s.value, env); return evalInputBlock(s.text, s.value, env);
} }
@ -157,13 +157,13 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved
} }
} }
export function evalCallBlock(fn: EditorState, input: EditorState, env): ResolvedType { export function evalCallBlock(fn: ExprBlockState, input: ExprBlockState, env): ResolvedType {
const fnResolved = evalEditorBlock(fn, env); const fnResolved = evalEditorBlock(fn, env);
const inputResolved = evalEditorBlock(input, env); const inputResolved = evalEditorBlock(input, env);
return evalCallBlock2(fnResolved, inputResolved, env); return evalCallBlock2(fnResolved, inputResolved, env);
} }
export function evalLetInBlock(value: EditorState, name: string, inner: EditorState, env): ResolvedType { export function evalLetInBlock(value: ExprBlockState, name: string, inner: ExprBlockState, env): ResolvedType {
const valueResolved = evalEditorBlock(value, env); const valueResolved = evalEditorBlock(value, env);
// console.log('eval', name, '...', valueResolved.kind, valueResolved.e); // console.log('eval', name, '...', valueResolved.kind, valueResolved.e);
// const innerEnv = growEnv(env)(name)(valueResolved); // const innerEnv = growEnv(env)(name)(valueResolved);
@ -183,7 +183,7 @@ export function getUnusedTypeVar(env) {
return TYPE_VARS[getUnusedTypeVarIdx(env)]; return TYPE_VARS[getUnusedTypeVarIdx(env)];
} }
export function evalLambdaBlock(paramName: string, expr: EditorState, env): ResolvedType { export function evalLambdaBlock(paramName: string, expr: ExprBlockState, env): ResolvedType {
const paramType = getUnusedTypeVar(env); const paramType = getUnusedTypeVar(env);
// static env: we only know the name and the type // static env: we only know the name and the type
const staticInnerEnv = growEnv(env)(paramName)({ const staticInnerEnv = growEnv(env)(paramName)({