blocking mode

This commit is contained in:
nora 2021-06-25 16:26:54 +02:00
parent 2202c79521
commit e9d3a88bb6
7 changed files with 63 additions and 27 deletions

2
bfi-rust/.gitignore vendored
View file

@ -1,5 +1,3 @@
/target /target
.idea .idea
# brainfuck testing code, get your own # brainfuck testing code, get your own
*.b
*.bf

View file

@ -34,6 +34,10 @@ $medium-color: #78787f;
height: 400px; height: 400px;
font-size: 100px; font-size: 100px;
} }
.code-options-wrapper > * {
margin: 10px;
}
} }
.code-display-wrapper { .code-display-wrapper {
@ -67,12 +71,18 @@ $medium-color: #78787f;
} }
} }
.run-button {
height: 50px;
width: 200px;
}
.bf-run { .bf-run {
margin: 20px; margin: 20px;
button {
height: 50px; .speed-control-wrapper > * {
width: 200px; margin: 10px;
} }
.small-speed-button { .small-speed-button {

View file

@ -1,11 +1,12 @@
import './App.scss'; import '../App.scss';
import CodeInput, {CodeOptions} from "./components/CodeInput"; import CodeInput, {CodeOptions} from "./CodeInput";
import ProgramOutput from "./components/ProgramOutput"; import ProgramOutput from "./ProgramOutput";
import React, {useCallback, useState} from "react"; import React, {useCallback, useState} from "react";
import Runner from "./components/Runner"; import Runner from "./Runner";
export const OptionContext = React.createContext<CodeOptions>({}); export const OptionContext = React.createContext<CodeOptions>({});
function App() { function App() {
const [out, setOut] = useState(""); const [out, setOut] = useState("");
const [input, setInput] = useState<[string, CodeOptions]>(["", {}]); const [input, setInput] = useState<[string, CodeOptions]>(["", {}]);

View file

@ -4,6 +4,7 @@ import presets from "../presets.json";
export interface CodeOptions { export interface CodeOptions {
minify?: boolean, minify?: boolean,
directStart?: boolean, directStart?: boolean,
startSuperSpeed?: boolean,
enableBreakpoints?: boolean enableBreakpoints?: boolean
asciiView?: boolean asciiView?: boolean
} }
@ -26,7 +27,7 @@ const CodeInput = ({input: [code, options], setInput}: CodeInputProps) => {
return ( return (
<div className="bf-input"> <div className="bf-input">
<div> <div className="code-options-wrapper">
<div> <div>
<label htmlFor="bf-input-fontsize-range">Font Size</label> <label htmlFor="bf-input-fontsize-range">Font Size</label>
<input type="range" id="bf-input-fontsize-range" onChange={v => setFontSize(+v.target.value)}/> <input type="range" id="bf-input-fontsize-range" onChange={v => setFontSize(+v.target.value)}/>
@ -35,6 +36,8 @@ const CodeInput = ({input: [code, options], setInput}: CodeInputProps) => {
<CodeOption displayName="Minify Code" name="minify" options={options} onChange={changeHandler}/> <CodeOption displayName="Minify Code" name="minify" options={options} onChange={changeHandler}/>
<CodeOption displayName="Start Directly" name="directStart" options={options} <CodeOption displayName="Start Directly" name="directStart" options={options}
onChange={changeHandler}/> onChange={changeHandler}/>
<CodeOption displayName="Start in blocking mode" name="startSuperSpeed" options={options}
onChange={changeHandler}/>
<CodeOption displayName="Breakpoints (•)" name="enableBreakpoints" options={options} <CodeOption displayName="Breakpoints (•)" name="enableBreakpoints" options={options}
onChange={changeHandler}/> onChange={changeHandler}/>
<CodeOption displayName="Show ASCII in memory" name="asciiView" options={options} <CodeOption displayName="Show ASCII in memory" name="asciiView" options={options}

View file

@ -1,6 +1,6 @@
import React, {useContext, useRef, useState} from 'react'; import React, {useContext, useRef, useState} from 'react';
import Interpreter from "../brainfuck/Interpreter"; import Interpreter from "../brainfuck/Interpreter";
import {OptionContext} from "../App"; import {OptionContext} from "./App";
const MAX_TABLE_COLUMNS = 20; const MAX_TABLE_COLUMNS = 20;

View file

@ -2,12 +2,13 @@ import React, {useCallback, useContext, useEffect, useRef, useState} from 'react
import Interpreter from "../brainfuck/Interpreter"; import Interpreter from "../brainfuck/Interpreter";
import CodeDisplay from "./CodeDisplay"; import CodeDisplay from "./CodeDisplay";
import RunDisplay from "./RunDisplay"; import RunDisplay from "./RunDisplay";
import {OptionContext} from "../App"; import {OptionContext} from "./App";
interface RunInfoProps { interface RunInfoProps {
code: string, running: boolean,
setRunning: (running: boolean) => void, setRunning: (running: boolean) => void,
running: boolean code: string,
outHandler: (char: number) => void, outHandler: (char: number) => void,
} }
@ -41,7 +42,11 @@ const Runner = ({setRunning, running, outHandler, code}: RunInfoProps) => {
const startHandler = useCallback(() => { const startHandler = useCallback(() => {
if (options.directStart) { if (options.directStart) {
setSpeed(100); if (options.startSuperSpeed) {
setSpeed(-1);
} else {
setSpeed(100);
}
} else { } else {
setSpeed(0); setSpeed(0);
} }
@ -72,20 +77,35 @@ const Runner = ({setRunning, running, outHandler, code}: RunInfoProps) => {
rerender(); rerender();
}, [interpreter, startTime]); }, [interpreter, startTime]);
const runBlocking = useCallback(() => {
try {
while (speed === -1 && !interpreter?.reachedEnd) {
interpreter?.next();
}
setSpeed(0);
setInfo(`Finished Execution. Took ${(Date.now() - startTime) / 1000}s`)
} catch (e) {
setInfo(e.message);
setSpeed(0);
}
}, [speed, interpreter, startTime]);
useEffect(() => { useEffect(() => {
if (running) { if (running) {
if (speed === 0) { if (speed === 0) {
return; return;
} }
const interval = setInterval(() => { if (speed > 0) {
nextHandler(); const interval = setInterval(() => {
}, 1000 / (speed * 10)); nextHandler();
}, 1000 / (speed * 10));
return () => clearInterval(interval); return () => clearInterval(interval);
}
runBlocking();
} }
}, [running, nextHandler, speed]); }, [runBlocking, running, nextHandler, speed]);
return ( return (
<div className="bf-run"> <div className="bf-run">
@ -96,9 +116,9 @@ const Runner = ({setRunning, running, outHandler, code}: RunInfoProps) => {
</> </>
} }
<div> <div>
{running && <button onClick={stopHandler}>Back</button>} {running && <button className="run-button" onClick={stopHandler}>Back</button>}
<button onClick={startHandler}>{running ? "Restart" : "Start"}</button> <button className="run-button" onClick={startHandler}>{running ? "Restart" : "Start"}</button>
{running && <button onClick={nextHandler}>Next</button>} {running && <button className="run-button" onClick={nextHandler}>Next</button>}
</div> </div>
{ {
running && interpreter && running && interpreter &&
@ -126,7 +146,7 @@ interface SpeedControlProps {
const SpeedControl = ({speed, setSpeed}: SpeedControlProps) => { const SpeedControl = ({speed, setSpeed}: SpeedControlProps) => {
return ( return (
<div> <div className="speed-control-wrapper">
<label htmlFor="run-info-speed-range">Speed</label> <label htmlFor="run-info-speed-range">Speed</label>
<input type="range" id="run-info-speed-range" value={speed} <input type="range" id="run-info-speed-range" value={speed}
onChange={e => setSpeed(+e.target.value)}/> onChange={e => setSpeed(+e.target.value)}/>
@ -139,6 +159,10 @@ const SpeedControl = ({speed, setSpeed}: SpeedControlProps) => {
<button onClick={() => setSpeed(s => s === 100 ? 100 : s + 1)} <button onClick={() => setSpeed(s => s === 100 ? 100 : s + 1)}
className="small-speed-button">+</button> className="small-speed-button">+</button>
</span> </span>
<span>
<label>Superspeed Mode (blocking)</label>
<input id="superspeed-mode-check" type="checkbox" checked={speed === -1} onChange={() => setSpeed(-1)}/>
</span>
</div> </div>
) )
} }

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import './index.css'; import './index.css';
import App from './App'; import App from './components/App';
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>