display dynamic errors too
This commit is contained in:
parent
abd3bd3645
commit
955bb17f9a
3 changed files with 46 additions and 17 deletions
|
|
@ -137,8 +137,10 @@ export function App() {
|
||||||
|
|
||||||
const currentState = appState.history.at(-1)!;
|
const currentState = appState.history.at(-1)!;
|
||||||
|
|
||||||
// infer types for entire app state
|
// static evalution
|
||||||
const typeInfo = useMemo(() => inferType(currentState, extendedEnv), [currentState]);
|
const typeInfo = useMemo(() => inferType(currentState, extendedEnv), [currentState]);
|
||||||
|
// dynamic evalutions
|
||||||
|
const evalResult = evalExpr(currentState, extendedEnv);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -186,7 +188,7 @@ export function App() {
|
||||||
/>
|
/>
|
||||||
=
|
=
|
||||||
<Value dynamic={{
|
<Value dynamic={{
|
||||||
i: evalExpr(currentState, extendedEnv),
|
i: evalResult.val,
|
||||||
t: typeInfo.type,
|
t: typeInfo.type,
|
||||||
}}/>
|
}}/>
|
||||||
::
|
::
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import { LambdaBlock, type LambdaBlockProps, type LambdaBlockState } from "./Lam
|
||||||
import { LetInBlock, type LetInBlockProps, type LetInBlockState } from "./LetInBlock";
|
import { LetInBlock, type LetInBlockProps, type LetInBlockState } from "./LetInBlock";
|
||||||
|
|
||||||
import "./ExprBlock.css";
|
import "./ExprBlock.css";
|
||||||
|
import { evalExpr } from "../../eval/eval";
|
||||||
|
|
||||||
export type ExprBlockState =
|
export type ExprBlockState =
|
||||||
InputBlockState
|
InputBlockState
|
||||||
|
|
@ -49,12 +50,13 @@ export function ExprBlock(props: ExprBlockProps) {
|
||||||
|
|
||||||
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(); }]));
|
||||||
return <span className={"editor" + (props.typeInfo.err ? " error" : "")}>
|
const err = props.typeInfo.err || evalExpr(props.state, env).err;
|
||||||
|
return <span className={"editor" + (err ? " error" : "")}>
|
||||||
{renderBlock[props.state.kind]()}
|
{renderBlock[props.state.kind]()}
|
||||||
{(props.typeInfo.err !== undefined) &&
|
{(err !== undefined) &&
|
||||||
(<div className="errorMessage">
|
(<div className="errorMessage">
|
||||||
{props.typeInfo.err.message.trim()}
|
{err.message.trim()}
|
||||||
</div>)}
|
</div>)}
|
||||||
<Input
|
<Input
|
||||||
placeholder="<c>"
|
placeholder="<c>"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@ export interface DynamicEnvironment {
|
||||||
names: any;
|
names: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EvalResult = any;
|
export interface EvalResult {
|
||||||
|
val?: any;
|
||||||
|
err?: Error;
|
||||||
|
};
|
||||||
|
|
||||||
export function evalExpr(s: ExprBlockState, env: DynamicEnvironment): EvalResult {
|
export function evalExpr(s: ExprBlockState, env: DynamicEnvironment): EvalResult {
|
||||||
if (s.kind === "input") {
|
if (s.kind === "input") {
|
||||||
|
|
@ -28,44 +31,65 @@ export function evalExpr(s: ExprBlockState, env: DynamicEnvironment): EvalResult
|
||||||
|
|
||||||
export function evalInput(s: InputBlockState, env: DynamicEnvironment): EvalResult {
|
export function evalInput(s: InputBlockState, env: DynamicEnvironment): EvalResult {
|
||||||
if (s.value.kind === "literal") {
|
if (s.value.kind === "literal") {
|
||||||
|
if (s.text === '') {
|
||||||
|
return {
|
||||||
|
err: new Error('cannot parse empty string as '+s.value.type)
|
||||||
|
};
|
||||||
|
}
|
||||||
const ctor = {
|
const ctor = {
|
||||||
Int: BigInt,
|
Int: BigInt,
|
||||||
Double: Number,
|
Double: Number,
|
||||||
}[s.value.type] as (s: string) => any;
|
}[s.value.type] as (s: string) => any;
|
||||||
return ctor(s.text);
|
return {
|
||||||
|
val: ctor(s.text)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else if (s.value.kind === "name") {
|
else if (s.value.kind === "name") {
|
||||||
const found = trie.get(env.names)(s.text);
|
const found = trie.get(env.names)(s.text);
|
||||||
if (found) {
|
if (found) {
|
||||||
if (found.recursive) {
|
if (found.recursive) {
|
||||||
|
// dirty
|
||||||
return found.i();
|
return found.i();
|
||||||
}
|
}
|
||||||
return found.i;
|
return {val: found.i};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
err: new Error(`'${s.text}' not found`),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function evalCall(s: CallBlockState, env: DynamicEnvironment): EvalResult {
|
export function evalCall(s: CallBlockState, env: DynamicEnvironment): EvalResult {
|
||||||
const fn = evalExpr(s.fn, env);
|
const fn = evalExpr(s.fn, env);
|
||||||
const input = evalExpr(s.input, env);
|
const input = evalExpr(s.input, env);
|
||||||
if (fn !== undefined && input !== undefined) {
|
if (fn.val !== undefined && input.val !== undefined) {
|
||||||
try {
|
try {
|
||||||
return fn(input);
|
const result = fn.val(input.val)
|
||||||
|
return { val: result } ;
|
||||||
|
}
|
||||||
|
catch (e: any) {
|
||||||
|
return { err: e };
|
||||||
}
|
}
|
||||||
catch {}
|
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function evalLet(s: LetInBlockState, env: DynamicEnvironment): EvalResult {
|
export function evalLet(s: LetInBlockState, env: DynamicEnvironment): EvalResult {
|
||||||
const valueEnv = {
|
const valueEnv = {
|
||||||
names: trie.insert(env.names)(s.name)({
|
names: trie.insert(env.names)(s.name)({
|
||||||
recursive: true,
|
recursive: true,
|
||||||
i: () => { try { return value; } catch (e) {} },
|
i: () => {
|
||||||
|
try {
|
||||||
|
return { val };
|
||||||
|
} catch (e) {
|
||||||
|
return { err: e };
|
||||||
|
}
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
const value = evalExpr(s.value, valueEnv);
|
const {val} = evalExpr(s.value, valueEnv);
|
||||||
const innerEnv = {
|
const innerEnv = {
|
||||||
names: trie.insert(env.names)(s.name)({i: value}),
|
names: trie.insert(env.names)(s.name)({i: val}),
|
||||||
}
|
}
|
||||||
return evalExpr(s.inner, innerEnv);
|
return evalExpr(s.inner, innerEnv);
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +99,8 @@ export function evalLambda(s: LambdaBlockState, env: DynamicEnvironment): EvalRe
|
||||||
const innerEnv = {
|
const innerEnv = {
|
||||||
names: trie.insert(env.names)(s.paramName)({i: x})
|
names: trie.insert(env.names)(s.paramName)({i: x})
|
||||||
};
|
};
|
||||||
return evalExpr(s.expr, innerEnv);
|
const result = evalExpr(s.expr, innerEnv);
|
||||||
|
return result.val;
|
||||||
};
|
};
|
||||||
return fn;
|
return {val: fn};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue