mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-16 14:25:03 +01:00
gh-pages :(
This commit is contained in:
parent
579d81021a
commit
296fd4a279
26 changed files with 533 additions and 381 deletions
|
|
@ -1,22 +1,22 @@
|
|||
import React from 'react';
|
||||
|
||||
interface CodeDisplayProps {
|
||||
code: string,
|
||||
index: number,
|
||||
}
|
||||
|
||||
const CodeDisplay = ({code, index}: CodeDisplayProps) => {
|
||||
|
||||
const firstCodePart = code.substr(0, index);
|
||||
const secondCodePart = code.substr(index + 1, code.length - index + 1);
|
||||
|
||||
return (
|
||||
<div className="code-display-wrapper">
|
||||
<span>{firstCodePart}</span>
|
||||
<span style={{backgroundColor: "red"}}>{code[index] || " "}</span>
|
||||
<span>{secondCodePart}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import React from 'react';
|
||||
|
||||
interface CodeDisplayProps {
|
||||
code: string,
|
||||
index: number,
|
||||
}
|
||||
|
||||
const CodeDisplay = ({code, index}: CodeDisplayProps) => {
|
||||
|
||||
const firstCodePart = code.substr(0, index);
|
||||
const secondCodePart = code.substr(index + 1, code.length - index + 1);
|
||||
|
||||
return (
|
||||
<div className="code-display-wrapper">
|
||||
<span>{firstCodePart}</span>
|
||||
<span style={{backgroundColor: "red"}}>{code[index] || " "}</span>
|
||||
<span>{secondCodePart}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CodeDisplay;
|
||||
|
|
@ -1,51 +1,51 @@
|
|||
import React, {useState} from 'react';
|
||||
|
||||
export interface CodeOptions {
|
||||
minify?: boolean
|
||||
}
|
||||
|
||||
interface CodeInputProps {
|
||||
setInput: ((code: string, options: CodeOptions) => void),
|
||||
code: string
|
||||
}
|
||||
|
||||
const CodeInput = ({code, setInput}: CodeInputProps) => {
|
||||
const [fontSize, setFontSize] = useState(40);
|
||||
|
||||
const [codeOptions, setCodeOptions] = useState<CodeOptions>({});
|
||||
|
||||
|
||||
const setStart = () => {
|
||||
setInput(
|
||||
"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.",
|
||||
codeOptions);
|
||||
}
|
||||
|
||||
const changeMinify = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setCodeOptions(old => ({...old, minify: e.target.checked}))
|
||||
setInput(code, codeOptions);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="bf-input">
|
||||
<div>
|
||||
<span>
|
||||
<label htmlFor="bf-input-fontsize-range">Font Size</label>
|
||||
<input type="range" id="bf-input-fontsize-range" onChange={v => setFontSize(+v.target.value)}/>
|
||||
</span>
|
||||
<input type="checkbox" checked={codeOptions.minify} id="input-options-minify" onChange={changeMinify}/>
|
||||
<label htmlFor="input-options-minify">Minify Code</label>
|
||||
</div>
|
||||
<textarea value={code} onChange={e => setInput(e.target.value, codeOptions)} style={{fontSize}}
|
||||
className="code-input"
|
||||
placeholder="Input your code here..."/>
|
||||
<div>
|
||||
<button onClick={setStart}>Set Hello World</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import React, {useState} from 'react';
|
||||
|
||||
export interface CodeOptions {
|
||||
minify?: boolean
|
||||
}
|
||||
|
||||
interface CodeInputProps {
|
||||
setInput: ((code: string, options: CodeOptions) => void),
|
||||
code: string
|
||||
}
|
||||
|
||||
const CodeInput = ({code, setInput}: CodeInputProps) => {
|
||||
const [fontSize, setFontSize] = useState(40);
|
||||
|
||||
const [codeOptions, setCodeOptions] = useState<CodeOptions>({});
|
||||
|
||||
|
||||
const setStart = () => {
|
||||
setInput(
|
||||
"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.",
|
||||
codeOptions);
|
||||
}
|
||||
|
||||
const changeMinify = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setCodeOptions(old => ({...old, minify: e.target.checked}))
|
||||
setInput(code, codeOptions);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="bf-input">
|
||||
<div>
|
||||
<span>
|
||||
<label htmlFor="bf-input-fontsize-range">Font Size</label>
|
||||
<input type="range" id="bf-input-fontsize-range" onChange={v => setFontSize(+v.target.value)}/>
|
||||
</span>
|
||||
<input type="checkbox" checked={codeOptions.minify} id="input-options-minify" onChange={changeMinify}/>
|
||||
<label htmlFor="input-options-minify">Minify Code</label>
|
||||
</div>
|
||||
<textarea value={code} onChange={e => setInput(e.target.value, codeOptions)} style={{fontSize}}
|
||||
className="code-input"
|
||||
placeholder="Input your code here..."/>
|
||||
<div>
|
||||
<button onClick={setStart}>Set Hello World</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CodeInput;
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
import React from 'react';
|
||||
|
||||
interface ProgramOutputProps {
|
||||
text: string
|
||||
}
|
||||
|
||||
const ProgramOutput = ({text}: ProgramOutputProps) => {
|
||||
return (
|
||||
<div className="bf-output">
|
||||
<textarea readOnly className="output-area" value={text}/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import React from 'react';
|
||||
|
||||
interface ProgramOutputProps {
|
||||
text: string
|
||||
}
|
||||
|
||||
const ProgramOutput = ({text}: ProgramOutputProps) => {
|
||||
return (
|
||||
<div className="bf-output">
|
||||
<textarea readOnly className="output-area" value={text}/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProgramOutput;
|
||||
|
|
@ -1,53 +1,53 @@
|
|||
import React from 'react';
|
||||
import Interpreter from "../brainfuck/Interpreter";
|
||||
|
||||
const MAX_TABLE_COLUMNS = 20;
|
||||
|
||||
interface RunDisplayProps {
|
||||
interpreter: Interpreter,
|
||||
}
|
||||
|
||||
const RunDisplay = ({interpreter}: RunDisplayProps) => {
|
||||
|
||||
const index = interpreter.pointer;
|
||||
|
||||
let offset: number;
|
||||
|
||||
if (index < MAX_TABLE_COLUMNS / 2) {
|
||||
offset = 0;
|
||||
} else {
|
||||
offset = index - MAX_TABLE_COLUMNS / 2;
|
||||
}
|
||||
|
||||
const arrayWithIndex = Array(MAX_TABLE_COLUMNS).fill(0)
|
||||
.map((_, i) => i + offset);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table className="memory-display-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{
|
||||
arrayWithIndex.map((n => <th key={n}>{n}</th>))
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
{
|
||||
arrayWithIndex.map((n) => <td className="cell" key={n}>{interpreter.array[n]}</td>)
|
||||
}
|
||||
</tr>
|
||||
<tr>
|
||||
{
|
||||
arrayWithIndex.map((n) => <td className="pointer"
|
||||
key={n}>{interpreter.pointer === n && "^"}</td>)
|
||||
}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import React from 'react';
|
||||
import Interpreter from "../brainfuck/Interpreter";
|
||||
|
||||
const MAX_TABLE_COLUMNS = 20;
|
||||
|
||||
interface RunDisplayProps {
|
||||
interpreter: Interpreter,
|
||||
}
|
||||
|
||||
const RunDisplay = ({interpreter}: RunDisplayProps) => {
|
||||
|
||||
const index = interpreter.pointer;
|
||||
|
||||
let offset: number;
|
||||
|
||||
if (index < MAX_TABLE_COLUMNS / 2) {
|
||||
offset = 0;
|
||||
} else {
|
||||
offset = index - MAX_TABLE_COLUMNS / 2;
|
||||
}
|
||||
|
||||
const arrayWithIndex = Array(MAX_TABLE_COLUMNS).fill(0)
|
||||
.map((_, i) => i + offset);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table className="memory-display-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{
|
||||
arrayWithIndex.map((n => <th key={n}>{n}</th>))
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
{
|
||||
arrayWithIndex.map((n) => <td className="cell" key={n}>{interpreter.array[n]}</td>)
|
||||
}
|
||||
</tr>
|
||||
<tr>
|
||||
{
|
||||
arrayWithIndex.map((n) => <td className="pointer"
|
||||
key={n}>{interpreter.pointer === n && "^"}</td>)
|
||||
}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RunDisplay;
|
||||
|
|
@ -1,107 +1,107 @@
|
|||
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
||||
import Interpreter from "../brainfuck/Interpreter";
|
||||
import CodeDisplay from "./CodeDisplay";
|
||||
import RunDisplay from "./RunDisplay";
|
||||
import {CodeOptions} from "./CodeInput";
|
||||
|
||||
interface RunInfoProps {
|
||||
input: [string, CodeOptions],
|
||||
setRunning: (running: boolean) => void,
|
||||
running: boolean
|
||||
outHandler: (char: number) => void,
|
||||
}
|
||||
|
||||
const Runner = ({setRunning, running, outHandler, input}: RunInfoProps) => {
|
||||
const [speed, setSpeed] = useState(0);
|
||||
const [interpreter, setInterpreter] = useState<Interpreter | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const [, setRerenderNumber] = useState(0);
|
||||
|
||||
const inputArea = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
|
||||
const inputHandler = () => {
|
||||
if (!inputArea.current) {
|
||||
throw new Error("Could not read input")
|
||||
}
|
||||
const value = inputArea.current.value;
|
||||
if (value.length < 1) {
|
||||
throw new Error("No input found");
|
||||
}
|
||||
const char = value.charCodeAt(0);
|
||||
inputArea.current.value = value.substr(1);
|
||||
return char;
|
||||
}
|
||||
|
||||
const errorHandler = (msg: string) => setError(msg);
|
||||
|
||||
const startHandler = useCallback(() => {
|
||||
setSpeed(0);
|
||||
setInterpreter(new Interpreter(input, outHandler, inputHandler, errorHandler));
|
||||
setRunning(false);
|
||||
setRunning(true);
|
||||
}, [input, outHandler, setRunning]);
|
||||
|
||||
const stopHandler = () => setRunning(false);
|
||||
|
||||
const nextHandler = useCallback(() => {
|
||||
setError(null);
|
||||
interpreter?.next();
|
||||
if (interpreter?.reachedEnd) {
|
||||
setSpeed(0);
|
||||
}
|
||||
setRerenderNumber(n => n + 1);
|
||||
}, [interpreter]);
|
||||
|
||||
useEffect(() => {
|
||||
if (running) {
|
||||
if (speed === 0) {
|
||||
return;
|
||||
}
|
||||
const interval = setInterval(() => {
|
||||
nextHandler();
|
||||
}, 1000 / (speed));
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [running, nextHandler, speed]);
|
||||
|
||||
|
||||
return (
|
||||
<div className="bf-run">
|
||||
{
|
||||
running && interpreter && <>
|
||||
<CodeDisplay code={interpreter.code} index={interpreter.programCounter}/>
|
||||
<RunDisplay interpreter={interpreter}/>
|
||||
</>
|
||||
}
|
||||
<div>
|
||||
<button onClick={stopHandler}>Back</button>
|
||||
<button onClick={startHandler}>Start</button>
|
||||
<button onClick={nextHandler}>Next</button>
|
||||
</div>
|
||||
{
|
||||
running && <>
|
||||
<div>
|
||||
<label htmlFor="run-info-speed-range">Speed</label>
|
||||
<input type="range" id="run-info-speed-range" value={speed}
|
||||
onChange={e => setSpeed(+e.target.value)}/>
|
||||
<span> {speed}</span>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
{
|
||||
error && <div className="error">{error}</div>
|
||||
}
|
||||
{
|
||||
running && <div>
|
||||
<div>Input:</div>
|
||||
<textarea className="program-input-area" ref={inputArea}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
||||
import Interpreter from "../brainfuck/Interpreter";
|
||||
import CodeDisplay from "./CodeDisplay";
|
||||
import RunDisplay from "./RunDisplay";
|
||||
import {CodeOptions} from "./CodeInput";
|
||||
|
||||
interface RunInfoProps {
|
||||
input: [string, CodeOptions],
|
||||
setRunning: (running: boolean) => void,
|
||||
running: boolean
|
||||
outHandler: (char: number) => void,
|
||||
}
|
||||
|
||||
const Runner = ({setRunning, running, outHandler, input}: RunInfoProps) => {
|
||||
const [speed, setSpeed] = useState(0);
|
||||
const [interpreter, setInterpreter] = useState<Interpreter | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const [, setRerenderNumber] = useState(0);
|
||||
|
||||
const inputArea = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
|
||||
const inputHandler = () => {
|
||||
if (!inputArea.current) {
|
||||
throw new Error("Could not read input")
|
||||
}
|
||||
const value = inputArea.current.value;
|
||||
if (value.length < 1) {
|
||||
throw new Error("No input found");
|
||||
}
|
||||
const char = value.charCodeAt(0);
|
||||
inputArea.current.value = value.substr(1);
|
||||
return char;
|
||||
}
|
||||
|
||||
const errorHandler = (msg: string) => setError(msg);
|
||||
|
||||
const startHandler = useCallback(() => {
|
||||
setSpeed(0);
|
||||
setInterpreter(new Interpreter(input, outHandler, inputHandler, errorHandler));
|
||||
setRunning(false);
|
||||
setRunning(true);
|
||||
}, [input, outHandler, setRunning]);
|
||||
|
||||
const stopHandler = () => setRunning(false);
|
||||
|
||||
const nextHandler = useCallback(() => {
|
||||
setError(null);
|
||||
interpreter?.next();
|
||||
if (interpreter?.reachedEnd) {
|
||||
setSpeed(0);
|
||||
}
|
||||
setRerenderNumber(n => n + 1);
|
||||
}, [interpreter]);
|
||||
|
||||
useEffect(() => {
|
||||
if (running) {
|
||||
if (speed === 0) {
|
||||
return;
|
||||
}
|
||||
const interval = setInterval(() => {
|
||||
nextHandler();
|
||||
}, 1000 / (speed));
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [running, nextHandler, speed]);
|
||||
|
||||
|
||||
return (
|
||||
<div className="bf-run">
|
||||
{
|
||||
running && interpreter && <>
|
||||
<CodeDisplay code={interpreter.code} index={interpreter.programCounter}/>
|
||||
<RunDisplay interpreter={interpreter}/>
|
||||
</>
|
||||
}
|
||||
<div>
|
||||
<button onClick={stopHandler}>Back</button>
|
||||
<button onClick={startHandler}>Start</button>
|
||||
<button onClick={nextHandler}>Next</button>
|
||||
</div>
|
||||
{
|
||||
running && <>
|
||||
<div>
|
||||
<label htmlFor="run-info-speed-range">Speed</label>
|
||||
<input type="range" id="run-info-speed-range" value={speed}
|
||||
onChange={e => setSpeed(+e.target.value)}/>
|
||||
<span> {speed}</span>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
{
|
||||
error && <div className="error">{error}</div>
|
||||
}
|
||||
{
|
||||
running && <div>
|
||||
<div>Input:</div>
|
||||
<textarea className="program-input-area" ref={inputArea}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Runner;
|
||||
Loading…
Add table
Add a link
Reference in a new issue