gh-pages :(

This commit is contained in:
nora 2021-06-24 15:26:43 +02:00
parent 579d81021a
commit 296fd4a279
26 changed files with 533 additions and 381 deletions

3
ibfi-ts/.gitignore vendored
View file

@ -8,9 +8,6 @@
# testing # testing
/coverage /coverage
# production
/build
# misc # misc
.DS_Store .DS_Store
.env.local .env.local

View file

@ -0,0 +1,20 @@
{
"files": {
"main.css": "/static/css/main.9eade52b.chunk.css",
"main.js": "/static/js/main.cb19c05d.chunk.js",
"main.js.map": "/static/js/main.cb19c05d.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.5aa3abe3.js",
"runtime-main.js.map": "/static/js/runtime-main.5aa3abe3.js.map",
"static/js/2.a611059c.chunk.js": "/static/js/2.a611059c.chunk.js",
"static/js/2.a611059c.chunk.js.map": "/static/js/2.a611059c.chunk.js.map",
"index.html": "/index.html",
"static/css/main.9eade52b.chunk.css.map": "/static/css/main.9eade52b.chunk.css.map",
"static/js/2.a611059c.chunk.js.LICENSE.txt": "/static/js/2.a611059c.chunk.js.LICENSE.txt"
},
"entrypoints": [
"static/js/runtime-main.5aa3abe3.js",
"static/js/2.a611059c.chunk.js",
"static/css/main.9eade52b.chunk.css",
"static/js/main.cb19c05d.chunk.js"
]
}

BIN
ibfi-ts/build/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

1
ibfi-ts/build/index.html Normal file
View file

@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><link href="/static/css/main.9eade52b.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,f=t[0],l=t[1],a=t[2],c=0,s=[];c<f.length;c++)i=f[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,a||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,f=1;f<r.length;f++){var l=r[f];0!==o[l]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/";var f=this["webpackJsonpibfi-ts"]=this["webpackJsonpibfi-ts"]||[],l=f.push.bind(f);f.push=t,f=f.slice();for(var a=0;a<f.length;a++)t(f[a]);var p=l;r()}([])</script><script src="/static/js/2.a611059c.chunk.js"></script><script src="/static/js/main.cb19c05d.chunk.js"></script></body></html>

BIN
ibfi-ts/build/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
ibfi-ts/build/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
ibfi-ts/build/robots.txt Normal file
View file

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View file

@ -0,0 +1,2 @@
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}.App{text-align:center}.App-logo{height:40vmin;pointer-events:none}.App-header{background-color:#282c34;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:calc(10px + 2vmin);color:#f8f8ff}.App-link{color:#61dafb}.bf-input .code-input{resize:none;width:80vw;height:400px;font-size:100px}.code-display-wrapper{max-width:80vw}.code-display-wrapper span{word-wrap:break-word}.memory-display-table .cell,.memory-display-table th{border:1px solid #f8f8ff}.memory-display-table td,.memory-display-table th{min-width:60px;text-align:center}.bf-run{margin:20px}.bf-run button{height:50px;width:200px}.bf-run .program-input-area{resize:none;width:80vw;height:50px;font-size:30px}.bf-run .error{background-color:#664242}.bf-output .output-area{resize:none;width:80vw;height:200px;font-size:20px}textarea{background-color:#323942;color:#f8f8ff}button{background-color:#78787f;font-size:20px;border:1px solid #282c34}button:hover{cursor:pointer;background-color:#f8f8ff}
/*# sourceMappingURL=main.9eade52b.chunk.css.map */

View file

@ -0,0 +1 @@
{"version":3,"sources":["webpack://src/index.css","webpack://src/App.scss"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,mJAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,yEAEF,CCPA,KACE,iBAAA,CAGF,UACE,aAAA,CACA,mBAAA,CAGF,YACE,wBAfW,CAgBX,gBAAA,CACA,YAAA,CACA,qBAAA,CACA,kBAAA,CACA,sBAAA,CACA,4BAAA,CACA,aApBY,CAuBd,UACE,aAAA,CAIA,sBACE,WAAA,CACA,UAAA,CACA,YAAA,CACA,eAAA,CAIJ,sBACE,cAAA,CAEA,2BACE,oBAAA,CAOF,qDACE,wBAHO,CAMT,kDACE,cAAA,CACA,iBAAA,CAIJ,QACE,WAAA,CAEA,eACE,WAAA,CACA,WAAA,CAGF,4BACE,WAAA,CACA,UAAA,CACA,WAAA,CACA,cAAA,CAGF,eACE,wBAAA,CAKF,wBACE,WAAA,CACA,UAAA,CACA,YAAA,CACA,cAAA,CAIJ,SACE,wBAxFoB,CAyFpB,aAxFY,CA2Fd,OACE,wBA3Fa,CA4Fb,cAAA,CACA,wBAAA,CAEA,aACE,cAAA,CACA,wBAlGU","file":"main.9eade52b.chunk.css","sourcesContent":["body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n monospace;\n}\n","$main-color: #282c34;\n$main-color-brighter: #323942;\n$light-color: ghostwhite;\n$medium-color: #78787f;\n\n.App {\n text-align: center;\n}\n\n.App-logo {\n height: 40vmin;\n pointer-events: none;\n}\n\n.App-header {\n background-color: $main-color;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: $light-color;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n.bf-input {\n .code-input {\n resize: none;\n width: 80vw;\n height: 400px;\n font-size: 100px;\n }\n}\n\n.code-display-wrapper {\n max-width: 80vw;\n\n span {\n word-wrap: break-word;\n }\n}\n\n.memory-display-table {\n $border: 1px solid $light-color;\n\n th, .cell {\n border: $border;\n }\n\n th, td {\n min-width: 60px;\n text-align: center;\n }\n}\n\n.bf-run {\n margin: 20px;\n\n button {\n height: 50px;\n width: 200px;\n }\n\n .program-input-area {\n resize: none;\n width: 80vw;\n height: 50px;\n font-size: 30px;\n }\n\n .error {\n background-color: #664242FF;\n }\n}\n\n.bf-output {\n .output-area {\n resize: none;\n width: 80vw;\n height: 200px;\n font-size: 20px;\n }\n}\n\ntextarea {\n background-color: $main-color-brighter;\n color: $light-color;\n}\n\nbutton {\n background-color: $medium-color;\n font-size: 20px;\n border: 1px solid $main-color;\n\n &:hover {\n cursor: pointer;\n background-color: $light-color;\n }\n}"]}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,41 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/** @license React v0.20.2
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
!function(e){function t(t){for(var n,i,f=t[0],l=t[1],a=t[2],c=0,s=[];c<f.length;c++)i=f[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,a||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,f=1;f<r.length;f++){var l=r[f];0!==o[l]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/";var f=this["webpackJsonpibfi-ts"]=this["webpackJsonpibfi-ts"]||[],l=f.push.bind(f);f.push=t,f=f.slice();for(var a=0;a<f.length;a++)t(f[a]);var p=l;r()}([]);
//# sourceMappingURL=runtime-main.5aa3abe3.js.map

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
{ {
"name": "ibfi-ts", "name": "ibfi-ts",
"version": "0.1.0", "version": "0.1.0",
"gomepage": "https://nilstrieb.github.io/brainfuck",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
@ -22,7 +23,9 @@
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject" "eject": "react-scripts eject",
"predeploy": "yarn build",
"deploy": "gh-pages -d build"
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
@ -41,5 +44,8 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"devDependencies": {
"gh-pages": "^3.2.3"
} }
} }

View file

@ -1,131 +1,131 @@
import {CodeOptions} from "../components/CodeInput"; import {CodeOptions} from "../components/CodeInput";
type InHandler = (() => number); type InHandler = (() => number);
type OutHandler = ((char: number) => void); type OutHandler = ((char: number) => void);
type ErrorHandler = ((msg: string) => void); type ErrorHandler = ((msg: string) => void);
export default class Interpreter { export default class Interpreter {
private readonly _array: Uint8Array; private readonly _array: Uint8Array;
private _pointer: number; private _pointer: number;
private readonly _code: string; private readonly _code: string;
private _programCounter: number; private _programCounter: number;
private readonly _inHandler: InHandler; private readonly _inHandler: InHandler;
private readonly _outHandler: OutHandler; private readonly _outHandler: OutHandler;
private readonly _errorHandler: ErrorHandler; private readonly _errorHandler: ErrorHandler;
constructor(input: [string, CodeOptions], outHandler: OutHandler, inHandler: InHandler, errorHandler: ErrorHandler) { constructor(input: [string, CodeOptions], outHandler: OutHandler, inHandler: InHandler, errorHandler: ErrorHandler) {
const buf = new ArrayBuffer(32000); const buf = new ArrayBuffer(32000);
this._array = new Uint8Array(buf); this._array = new Uint8Array(buf);
this._pointer = 0; this._pointer = 0;
if (input[1].minify) { if (input[1].minify) {
this._code = minify(input[0]) this._code = minify(input[0])
} else { } else {
this._code = input[0]; this._code = input[0];
} }
this._programCounter = 0; this._programCounter = 0;
this._inHandler = inHandler; this._inHandler = inHandler;
this._outHandler = outHandler; this._outHandler = outHandler;
this._errorHandler = errorHandler; this._errorHandler = errorHandler;
} }
public next() { public next() {
switch (this._code[this._programCounter++]) { switch (this._code[this._programCounter++]) {
case '+': case '+':
this._array[this._pointer]++; this._array[this._pointer]++;
break; break;
case '-': case '-':
this._array[this._pointer]--; this._array[this._pointer]--;
break; break;
case '>': case '>':
this._pointer++; this._pointer++;
break; break;
case '<': case '<':
if (this._pointer === 0) { if (this._pointer === 0) {
this._errorHandler("Cannot wrap left"); this._errorHandler("Cannot wrap left");
break; break;
} }
this._pointer--; this._pointer--;
break; break;
case '.': case '.':
this._outHandler(this.value); this._outHandler(this.value);
break; break;
case ',': case ',':
try { try {
this._array[this._pointer] = this._inHandler(); this._array[this._pointer] = this._inHandler();
} catch { } catch {
this._programCounter--; this._programCounter--;
this._errorHandler("Could not read input, trying again next time.") this._errorHandler("Could not read input, trying again next time.")
} }
break; break;
case '[': case '[':
if (this.value === 0) { if (this.value === 0) {
let level = 0; let level = 0;
while (this.lastInstruction !== ']' || level > -1) { while (this.lastInstruction !== ']' || level > -1) {
this._programCounter++; this._programCounter++;
if (this.lastInstruction === '[') level++; if (this.lastInstruction === '[') level++;
else if (this.lastInstruction === ']') level--; else if (this.lastInstruction === ']') level--;
} }
} }
break; break;
case ']': case ']':
if (this.value !== 0) { if (this.value !== 0) {
let level = 0; let level = 0;
while (this.lastInstruction !== '[' || level > -1) { while (this.lastInstruction !== '[' || level > -1) {
this._programCounter--; this._programCounter--;
if (this.lastInstruction === '[') level--; if (this.lastInstruction === '[') level--;
else if (this.lastInstruction === ']') level++; else if (this.lastInstruction === ']') level++;
} }
} }
break; break;
case undefined: case undefined:
this._pointer = this._code.length; this._pointer = this._code.length;
console.warn("reached end"); console.warn("reached end");
break; break;
default: { default: {
} }
} }
console.log(`char: ${this.code[this.programCounter - 1]} pointer: ${this.pointer} value: ${this.array[this.pointer]}`) console.log(`char: ${this.code[this.programCounter - 1]} pointer: ${this.pointer} value: ${this.array[this.pointer]}`)
} }
public prev() { public prev() {
} }
get reachedEnd(): boolean { get reachedEnd(): boolean {
return this._programCounter === this._code.length; return this._programCounter === this._code.length;
} }
get lastInstruction(): string { get lastInstruction(): string {
return this._code[this._programCounter - 1]; return this._code[this._programCounter - 1];
} }
get value(): number { get value(): number {
return this._array[this._pointer]; return this._array[this._pointer];
} }
get array(): Uint8Array { get array(): Uint8Array {
return this._array; return this._array;
} }
get pointer(): number { get pointer(): number {
return this._pointer; return this._pointer;
} }
get code(): string { get code(): string {
return this._code; return this._code;
} }
get programCounter(): number { get programCounter(): number {
return this._programCounter; return this._programCounter;
} }
} }
const CHARS = ['+', '-', '<', '>', '.', ',', '[', ']']; const CHARS = ['+', '-', '<', '>', '.', ',', '[', ']'];
const minify = (code: string): string => const minify = (code: string): string =>
code.split("") code.split("")
.filter(c => CHARS.includes(c)) .filter(c => CHARS.includes(c))
.join(""); .join("");

View file

@ -1,22 +1,22 @@
import React from 'react'; import React from 'react';
interface CodeDisplayProps { interface CodeDisplayProps {
code: string, code: string,
index: number, index: number,
} }
const CodeDisplay = ({code, index}: CodeDisplayProps) => { const CodeDisplay = ({code, index}: CodeDisplayProps) => {
const firstCodePart = code.substr(0, index); const firstCodePart = code.substr(0, index);
const secondCodePart = code.substr(index + 1, code.length - index + 1); const secondCodePart = code.substr(index + 1, code.length - index + 1);
return ( return (
<div className="code-display-wrapper"> <div className="code-display-wrapper">
<span>{firstCodePart}</span> <span>{firstCodePart}</span>
<span style={{backgroundColor: "red"}}>{code[index] || " "}</span> <span style={{backgroundColor: "red"}}>{code[index] || " "}</span>
<span>{secondCodePart}</span> <span>{secondCodePart}</span>
</div> </div>
); );
}; };
export default CodeDisplay; export default CodeDisplay;

View file

@ -1,51 +1,51 @@
import React, {useState} from 'react'; import React, {useState} from 'react';
export interface CodeOptions { export interface CodeOptions {
minify?: boolean minify?: boolean
} }
interface CodeInputProps { interface CodeInputProps {
setInput: ((code: string, options: CodeOptions) => void), setInput: ((code: string, options: CodeOptions) => void),
code: string code: string
} }
const CodeInput = ({code, setInput}: CodeInputProps) => { const CodeInput = ({code, setInput}: CodeInputProps) => {
const [fontSize, setFontSize] = useState(40); const [fontSize, setFontSize] = useState(40);
const [codeOptions, setCodeOptions] = useState<CodeOptions>({}); const [codeOptions, setCodeOptions] = useState<CodeOptions>({});
const setStart = () => { const setStart = () => {
setInput( setInput(
"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.", "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.",
codeOptions); codeOptions);
} }
const changeMinify = (e: React.ChangeEvent<HTMLInputElement>) => { const changeMinify = (e: React.ChangeEvent<HTMLInputElement>) => {
setCodeOptions(old => ({...old, minify: e.target.checked})) setCodeOptions(old => ({...old, minify: e.target.checked}))
setInput(code, codeOptions); setInput(code, codeOptions);
} }
return ( return (
<div> <div>
<div className="bf-input"> <div className="bf-input">
<div> <div>
<span> <span>
<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)}/>
</span> </span>
<input type="checkbox" checked={codeOptions.minify} id="input-options-minify" onChange={changeMinify}/> <input type="checkbox" checked={codeOptions.minify} id="input-options-minify" onChange={changeMinify}/>
<label htmlFor="input-options-minify">Minify Code</label> <label htmlFor="input-options-minify">Minify Code</label>
</div> </div>
<textarea value={code} onChange={e => setInput(e.target.value, codeOptions)} style={{fontSize}} <textarea value={code} onChange={e => setInput(e.target.value, codeOptions)} style={{fontSize}}
className="code-input" className="code-input"
placeholder="Input your code here..."/> placeholder="Input your code here..."/>
<div> <div>
<button onClick={setStart}>Set Hello World</button> <button onClick={setStart}>Set Hello World</button>
</div> </div>
</div> </div>
</div> </div>
); );
}; };
export default CodeInput; export default CodeInput;

View file

@ -1,15 +1,15 @@
import React from 'react'; import React from 'react';
interface ProgramOutputProps { interface ProgramOutputProps {
text: string text: string
} }
const ProgramOutput = ({text}: ProgramOutputProps) => { const ProgramOutput = ({text}: ProgramOutputProps) => {
return ( return (
<div className="bf-output"> <div className="bf-output">
<textarea readOnly className="output-area" value={text}/> <textarea readOnly className="output-area" value={text}/>
</div> </div>
); );
}; };
export default ProgramOutput; export default ProgramOutput;

View file

@ -1,53 +1,53 @@
import React from 'react'; import React from 'react';
import Interpreter from "../brainfuck/Interpreter"; import Interpreter from "../brainfuck/Interpreter";
const MAX_TABLE_COLUMNS = 20; const MAX_TABLE_COLUMNS = 20;
interface RunDisplayProps { interface RunDisplayProps {
interpreter: Interpreter, interpreter: Interpreter,
} }
const RunDisplay = ({interpreter}: RunDisplayProps) => { const RunDisplay = ({interpreter}: RunDisplayProps) => {
const index = interpreter.pointer; const index = interpreter.pointer;
let offset: number; let offset: number;
if (index < MAX_TABLE_COLUMNS / 2) { if (index < MAX_TABLE_COLUMNS / 2) {
offset = 0; offset = 0;
} else { } else {
offset = index - MAX_TABLE_COLUMNS / 2; offset = index - MAX_TABLE_COLUMNS / 2;
} }
const arrayWithIndex = Array(MAX_TABLE_COLUMNS).fill(0) const arrayWithIndex = Array(MAX_TABLE_COLUMNS).fill(0)
.map((_, i) => i + offset); .map((_, i) => i + offset);
return ( return (
<div> <div>
<table className="memory-display-table"> <table className="memory-display-table">
<thead> <thead>
<tr> <tr>
{ {
arrayWithIndex.map((n => <th key={n}>{n}</th>)) arrayWithIndex.map((n => <th key={n}>{n}</th>))
} }
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
{ {
arrayWithIndex.map((n) => <td className="cell" key={n}>{interpreter.array[n]}</td>) arrayWithIndex.map((n) => <td className="cell" key={n}>{interpreter.array[n]}</td>)
} }
</tr> </tr>
<tr> <tr>
{ {
arrayWithIndex.map((n) => <td className="pointer" arrayWithIndex.map((n) => <td className="pointer"
key={n}>{interpreter.pointer === n && "^"}</td>) key={n}>{interpreter.pointer === n && "^"}</td>)
} }
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
); );
}; };
export default RunDisplay; export default RunDisplay;

View file

@ -1,107 +1,107 @@
import React, {useCallback, useEffect, useRef, useState} from 'react'; import React, {useCallback, 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 {CodeOptions} from "./CodeInput"; import {CodeOptions} from "./CodeInput";
interface RunInfoProps { interface RunInfoProps {
input: [string, CodeOptions], input: [string, CodeOptions],
setRunning: (running: boolean) => void, setRunning: (running: boolean) => void,
running: boolean running: boolean
outHandler: (char: number) => void, outHandler: (char: number) => void,
} }
const Runner = ({setRunning, running, outHandler, input}: RunInfoProps) => { const Runner = ({setRunning, running, outHandler, input}: RunInfoProps) => {
const [speed, setSpeed] = useState(0); const [speed, setSpeed] = useState(0);
const [interpreter, setInterpreter] = useState<Interpreter | null>(null); const [interpreter, setInterpreter] = useState<Interpreter | null>(null);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [, setRerenderNumber] = useState(0); const [, setRerenderNumber] = useState(0);
const inputArea = useRef<HTMLTextAreaElement>(null); const inputArea = useRef<HTMLTextAreaElement>(null);
const inputHandler = () => { const inputHandler = () => {
if (!inputArea.current) { if (!inputArea.current) {
throw new Error("Could not read input") throw new Error("Could not read input")
} }
const value = inputArea.current.value; const value = inputArea.current.value;
if (value.length < 1) { if (value.length < 1) {
throw new Error("No input found"); throw new Error("No input found");
} }
const char = value.charCodeAt(0); const char = value.charCodeAt(0);
inputArea.current.value = value.substr(1); inputArea.current.value = value.substr(1);
return char; return char;
} }
const errorHandler = (msg: string) => setError(msg); const errorHandler = (msg: string) => setError(msg);
const startHandler = useCallback(() => { const startHandler = useCallback(() => {
setSpeed(0); setSpeed(0);
setInterpreter(new Interpreter(input, outHandler, inputHandler, errorHandler)); setInterpreter(new Interpreter(input, outHandler, inputHandler, errorHandler));
setRunning(false); setRunning(false);
setRunning(true); setRunning(true);
}, [input, outHandler, setRunning]); }, [input, outHandler, setRunning]);
const stopHandler = () => setRunning(false); const stopHandler = () => setRunning(false);
const nextHandler = useCallback(() => { const nextHandler = useCallback(() => {
setError(null); setError(null);
interpreter?.next(); interpreter?.next();
if (interpreter?.reachedEnd) { if (interpreter?.reachedEnd) {
setSpeed(0); setSpeed(0);
} }
setRerenderNumber(n => n + 1); setRerenderNumber(n => n + 1);
}, [interpreter]); }, [interpreter]);
useEffect(() => { useEffect(() => {
if (running) { if (running) {
if (speed === 0) { if (speed === 0) {
return; return;
} }
const interval = setInterval(() => { const interval = setInterval(() => {
nextHandler(); nextHandler();
}, 1000 / (speed)); }, 1000 / (speed));
return () => clearInterval(interval); return () => clearInterval(interval);
} }
}, [running, nextHandler, speed]); }, [running, nextHandler, speed]);
return ( return (
<div className="bf-run"> <div className="bf-run">
{ {
running && interpreter && <> running && interpreter && <>
<CodeDisplay code={interpreter.code} index={interpreter.programCounter}/> <CodeDisplay code={interpreter.code} index={interpreter.programCounter}/>
<RunDisplay interpreter={interpreter}/> <RunDisplay interpreter={interpreter}/>
</> </>
} }
<div> <div>
<button onClick={stopHandler}>Back</button> <button onClick={stopHandler}>Back</button>
<button onClick={startHandler}>Start</button> <button onClick={startHandler}>Start</button>
<button onClick={nextHandler}>Next</button> <button onClick={nextHandler}>Next</button>
</div> </div>
{ {
running && <> running && <>
<div> <div>
<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)}/>
<span> {speed}</span> <span> {speed}</span>
</div> </div>
</> </>
} }
{ {
error && <div className="error">{error}</div> error && <div className="error">{error}</div>
} }
{ {
running && <div> running && <div>
<div>Input:</div> <div>Input:</div>
<textarea className="program-input-area" ref={inputArea}/> <textarea className="program-input-area" ref={inputArea}/>
</div> </div>
} }
</div> </div>
); );
}; };
export default Runner; export default Runner;

View file

@ -1 +1 @@
/// <reference types="react-scripts" /> /// <reference types="react-scripts" />

View file

@ -2521,7 +2521,7 @@ async-limiter@~1.0.0:
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
async@^2.6.2: async@^2.6.1, async@^2.6.2:
version "2.6.3" version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
@ -3445,7 +3445,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
commander@^2.20.0: commander@^2.18.0, commander@^2.20.0:
version "2.20.3" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -4347,6 +4347,11 @@ elliptic@^6.5.3:
minimalistic-assert "^1.0.1" minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1" minimalistic-crypto-utils "^1.0.1"
email-addresses@^3.0.1:
version "3.1.0"
resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.1.0.tgz#cabf7e085cbdb63008a70319a74e6136188812fb"
integrity sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==
emittery@^0.7.1: emittery@^0.7.1:
version "0.7.2" version "0.7.2"
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82"
@ -5041,6 +5046,20 @@ file-uri-to-path@1.0.0:
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
filename-reserved-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229"
integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik=
filenamify@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-4.3.0.tgz#62391cb58f02b09971c9d4f9d63b3cf9aba03106"
integrity sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==
dependencies:
filename-reserved-regex "^2.0.0"
strip-outer "^1.0.1"
trim-repeated "^1.0.0"
filesize@6.1.0: filesize@6.1.0:
version "6.1.0" version "6.1.0"
resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00" resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00"
@ -5366,6 +5385,19 @@ getpass@^0.1.1:
dependencies: dependencies:
assert-plus "^1.0.0" assert-plus "^1.0.0"
gh-pages@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-3.2.3.tgz#897e5f15e111f42af57d21d430b83e5cdf29472c"
integrity sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==
dependencies:
async "^2.6.1"
commander "^2.18.0"
email-addresses "^3.0.1"
filenamify "^4.3.0"
find-cache-dir "^3.3.1"
fs-extra "^8.1.0"
globby "^6.1.0"
glob-parent@^3.1.0: glob-parent@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
@ -10701,6 +10733,13 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
strip-outer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631"
integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==
dependencies:
escape-string-regexp "^1.0.2"
style-loader@1.3.0: style-loader@1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e"
@ -11003,6 +11042,13 @@ trim-newlines@^1.0.0:
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
trim-repeated@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21"
integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE=
dependencies:
escape-string-regexp "^1.0.2"
"true-case-path@^1.0.2": "true-case-path@^1.0.2":
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"