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
/coverage
# production
/build
# misc
.DS_Store
.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",
"version": "0.1.0",
"gomepage": "https://nilstrieb.github.io/brainfuck",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.11.4",
@ -22,7 +23,9 @@
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"predeploy": "yarn build",
"deploy": "gh-pages -d build"
},
"eslintConfig": {
"extends": [
@ -41,5 +44,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"gh-pages": "^3.2.3"
}
}

View file

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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

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"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
async@^2.6.2:
async@^2.6.1, async@^2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
@ -3445,7 +3445,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
commander@^2.20.0:
commander@^2.18.0, commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -4347,6 +4347,11 @@ elliptic@^6.5.3:
minimalistic-assert "^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:
version "0.7.2"
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"
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:
version "6.1.0"
resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00"
@ -5366,6 +5385,19 @@ getpass@^0.1.1:
dependencies:
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:
version "3.1.0"
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"
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:
version "1.3.0"
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"
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":
version "1.0.3"
resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"