This commit is contained in:
nora 2021-06-24 11:02:50 +02:00
parent e815fd8c66
commit 5f6d1d5b4b
8 changed files with 225 additions and 52 deletions

View file

@ -0,0 +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>
);
};
export default CodeDisplay;

View file

@ -7,14 +7,23 @@ interface CodeInputProps {
const CodeInput = ({setInput}: CodeInputProps) => {
const [fontSize, setFontSize] = useState(40);
const setStart = () => {
setInput(
"+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+."
+ "+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+."
);
}
return (
<div>
<div className="bf-input">
<div>
<label htmlFor="bf-input-fontsize-range">Font Size</label>
<input type="range" id="bf-input-fontsize-range" onChange={v => setFontSize(+v.target.value)}/>
<button onClick={setStart}>set init</button>
</div>
<textarea onChange={e => setInput(e.target.value)} style={{fontSize}} className="code-input" placeholder="Input your code here..."/>
<textarea onChange={e => setInput(e.target.value)} style={{fontSize}} className="code-input"
placeholder="Input your code here..."/>
</div>
</div>
);

View file

@ -0,0 +1,52 @@
import React from 'react';
import Interpreter from "../brainfuck/Interpreter";
const MAX_TABLE_COLUMNS = 30;
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;

View file

@ -1,28 +0,0 @@
import React from 'react';
import Interpreter from "../brainfuck/Interpreter";
interface RunInfoProps {
nextHandler: () => void,
prevHandler: () => void,
startHandler: () => void,
interpreter: Interpreter | null,
}
const RunInfo = ({interpreter, ...props}: RunInfoProps) => {
return (
<div className="bf-run">
<div>
<button onClick={props.startHandler}>Start</button>
<button onClick={props.nextHandler}>Next</button>
<button onClick={props.prevHandler}>Previous</button>
</div>
{interpreter &&
<div>Pointer: {interpreter.pointer} value {interpreter.value}</div>
}
</div>
);
}
;
export default RunInfo;

View file

@ -0,0 +1,75 @@
import React, {useCallback, useEffect, useState} from 'react';
import Interpreter from "../brainfuck/Interpreter";
import CodeDisplay from "./CodeDisplay";
import RunDisplay from "./RunDisplay";
interface RunInfoProps {
input: string,
setRunning: (running: boolean) => void,
running: boolean
inHandler: () => number,
outHandler: (char: number) => void,
}
const Runner = ({setRunning, running, inHandler, outHandler, input}: RunInfoProps) => {
const [speed, setSpeed] = useState(0);
const [interpreter, setInterpreter] = useState<Interpreter | null>(null);
const [, setRerenderNumber] = useState(0);
const startHandler = useCallback(() => {
setSpeed(0);
setInterpreter(new Interpreter(input, outHandler, inHandler));
setRunning(true);
}, [input, inHandler, outHandler, setRunning]);
const stopHandler = () => setRunning(false);
const nextHandler = useCallback(() => {
interpreter?.next();
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={input} index={interpreter.codePointer}/>
<RunDisplay interpreter={interpreter}/>
</>
}
<div>
<button onClick={startHandler}>Start</button>
<button onClick={stopHandler}>Stop</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>
</>
}
</div>
);
}
;
export default Runner;