99 lines
3 KiB
TypeScript
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>
|
|
);
|
|
}
|
|
|