scrowl/src/ui/Digith/REPL.tsx
2026-04-06 20:34:20 +02:00

99 lines
3 KiB
TypeScript

import { createSignal, Match, Switch } from 'solid-js';
import { useProgram } from 'src/ui/ProgramProvider';
import { eval_start } from 'src/lang/eval/evaluator';
import { Value } from 'src/lang/eval/value';
import { RuntimeError } from 'src/lang/eval/error';
import { SourceRegion, SourceText, sourceText } from 'source-region';
import { ParseError, parseExpr } from 'src/lang/parser/parser';
import { ShowParseError } from 'src/ui/Component/ParseError';
import { Val } from 'src/ui/Component/Value';
import { CodeEditor } from 'src/ui/Component/CodeEditor';
namespace ReplResult {
export type Idle =
{ tag: "idle" }
export type Success =
{ tag: "success", value: Value }
export type Parse_Error =
{ tag: "parse_error", text: SourceRegion, err: ParseError }
export type Runtime_Error =
{ tag: "runtime_error", err: RuntimeError }
}
type ReplResult =
| ReplResult.Idle
| ReplResult.Success
| ReplResult.Parse_Error
| ReplResult.Runtime_Error
export function ExprREPL() {
const program = useProgram();
const [input, setInput] = createSignal("");
const [result, setResult] = createSignal<ReplResult>({ tag: "idle" });
function runExecution() {
const raw = input();
if (input().trim() === "") {
return;
}
const text = sourceText(raw).fullRegion();
const parseResult = parseExpr(text);
if (parseResult.tag === "error") {
setResult({ tag: "parse_error", text: text, err: parseResult.error });
} else {
const evalResult = eval_start(program, parseResult.value);
if (evalResult.tag === "ok") {
setResult({ tag: "success", value: evalResult.value });
} else {
setResult({ tag: "runtime_error", err: evalResult.error });
}
}
}
return (
<section>
<CodeEditor
value={input()}
onUpdate={setInput}
onRun={runExecution}
/>
<button onClick={runExecution}>Run</button>
<div style={{ "margin-top": "1rem" }}>
<Switch>
<Match when={result().tag === "idle"}>
{ "" }
</Match>
<Match when={result().tag === "success" && result() as ReplResult.Success }>
{(res) => (
<article>
<header>Result</header>
<Val value={ res().value } />
</article>
)}
</Match>
<Match when={result().tag === "parse_error" && result() as ReplResult.Parse_Error }>
{(res) => (
<ShowParseError text={res().text} err={res().err} />
)}
</Match>
<Match when={result().tag === "runtime_error" && result() as ReplResult.Runtime_Error }>
{(res) => (
<article style={{ "border-color": "var(--pico-del-color)" }}>
<header style={{ color: "var(--pico-del-color)" }}>Runtime Error</header>
<pre>{JSON.stringify(res().err, null, 2)}</pre>
</article>
)}
</Match>
</Switch>
</div>
</section>
);
}