diff --git a/ibfi-ts/src/App.scss b/ibfi-ts/src/App.scss
index 8316c9a..adfc14f 100644
--- a/ibfi-ts/src/App.scss
+++ b/ibfi-ts/src/App.scss
@@ -1,6 +1,7 @@
$main-color: #282c34;
$main-color-brighter: #323942;
-$font-color: ghostwhite;
+$light-color: ghostwhite;
+$medium-color: #78787f;
.App {
text-align: center;
@@ -19,7 +20,7 @@ $font-color: ghostwhite;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
- color: $font-color;
+ color: $light-color;
}
.App-link {
@@ -44,7 +45,7 @@ $font-color: ghostwhite;
}
.memory-display-table {
- $border: 1px solid $font-color;
+ $border: 1px solid $light-color;
th, .cell {
border: $border;
@@ -67,6 +68,10 @@ $font-color: ghostwhite;
height: 50px;
width: 200px;
}
+
+ .error {
+ background-color: #664242FF;
+ }
}
.bf-output {
@@ -80,5 +85,16 @@ $font-color: ghostwhite;
textarea {
background-color: $main-color-brighter;
- color: $font-color;
+ color: $light-color;
+}
+
+button {
+ background-color: $medium-color;
+ font-size: 20px;
+ border: 1px solid $main-color;
+
+ &:hover {
+ cursor: pointer;
+ background-color: $light-color;
+ }
}
\ No newline at end of file
diff --git a/ibfi-ts/src/App.tsx b/ibfi-ts/src/App.tsx
index da6bf5b..b719e72 100644
--- a/ibfi-ts/src/App.tsx
+++ b/ibfi-ts/src/App.tsx
@@ -17,12 +17,19 @@ function App() {
return 65;
}, []);
+ const runHandler = (run: boolean) => {
+ setRunning(run);
+ if (!run) {
+ setOut("");
+ }
+ }
+
return (
{
!running &&
setInput(input)}/>
}
-
+
{
running &&
}
diff --git a/ibfi-ts/src/brainfuck/Interpreter.ts b/ibfi-ts/src/brainfuck/Interpreter.ts
index ab40799..82cc6b8 100644
--- a/ibfi-ts/src/brainfuck/Interpreter.ts
+++ b/ibfi-ts/src/brainfuck/Interpreter.ts
@@ -1,13 +1,18 @@
+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 _codePointer: number;
- private readonly _inHandler: (() => number);
- private readonly _outHandler: ((char: number) => void);
+ private readonly _inHandler: InHandler;
+ private readonly _outHandler: OutHandler;
+ private readonly _errorHandler: ErrorHandler;
- constructor(code: string, outHandler: ((char: number) => void), inHandler: (() => number)) {
+ constructor(code: string, outHandler: OutHandler, inHandler: InHandler, errorHandler: ErrorHandler) {
const buf = new ArrayBuffer(32000);
this._array = new Uint8Array(buf);
this._pointer = 0;
@@ -15,6 +20,7 @@ export default class Interpreter {
this._codePointer = 0;
this._inHandler = inHandler;
this._outHandler = outHandler;
+ this._errorHandler = errorHandler;
}
public next() {
@@ -29,6 +35,10 @@ export default class Interpreter {
this._pointer++;
break;
case '<':
+ if (this._pointer === 0) {
+ this._errorHandler("Cannot wrap left");
+ break;
+ }
this._pointer--;
break;
case '.':
@@ -40,24 +50,25 @@ export default class Interpreter {
case '[':
if (this.value === 0) {
let level = 0;
- while (this.instruction !== ']' || level > -1) {
+ while (this.lastInstruction !== ']' || level > -1) {
this._codePointer++;
- if (this.instruction === '[') level++;
- else if (this.instruction === ']') level--;
+ if (this.lastInstruction === '[') level++;
+ else if (this.lastInstruction === ']') level--;
}
}
break;
case ']':
if (this.value !== 0) {
let level = 0;
- while (this.instruction !== '[' || level > -1) {
+ while (this.lastInstruction !== '[' || level > -1) {
this._codePointer--;
- if (this.instruction === '[') level--;
- else if (this.instruction === ']') level++;
+ if (this.lastInstruction === '[') level--;
+ else if (this.lastInstruction === ']') level++;
}
}
break;
case undefined:
+ this._pointer--;
console.warn("reached end");
break;
default: {
@@ -70,8 +81,12 @@ export default class Interpreter {
}
- get instruction(): string {
- return this._code[this._codePointer];
+ get reachedEnd(): boolean {
+ return this._codePointer === this._code.length - 1;
+ }
+
+ get lastInstruction(): string {
+ return this._code[this._codePointer - 1];
}
get value(): number {
diff --git a/ibfi-ts/src/components/Runner.tsx b/ibfi-ts/src/components/Runner.tsx
index ce48d5a..c62112d 100644
--- a/ibfi-ts/src/components/Runner.tsx
+++ b/ibfi-ts/src/components/Runner.tsx
@@ -12,64 +12,76 @@ interface RunInfoProps {
}
const Runner = ({setRunning, running, inHandler, outHandler, input}: RunInfoProps) => {
- const [speed, setSpeed] = useState(0);
- const [interpreter, setInterpreter] = useState(null);
+ const [speed, setSpeed] = useState(0);
+ const [interpreter, setInterpreter] = useState(null);
+ const [error, setError] = useState(null);
- const [, setRerenderNumber] = useState(0);
+ const [, setRerenderNumber] = useState(0);
- const startHandler = useCallback(() => {
+ const errorHandler = (msg: string) => {
+ setError(msg);
+ }
+
+ const startHandler = useCallback(() => {
+ setSpeed(0);
+ setInterpreter(new Interpreter(input, outHandler, inHandler, errorHandler));
+ setRunning(false);
+ setRunning(true);
+ }, [input, inHandler, outHandler, setRunning]);
+
+ const stopHandler = () => setRunning(false);
+
+ const nextHandler = useCallback(() => {
+ setError(null);
+ interpreter?.next();
+ if (interpreter?.reachedEnd) {
setSpeed(0);
- setInterpreter(new Interpreter(input, outHandler, inHandler));
- setRunning(true);
- }, [input, inHandler, outHandler, setRunning]);
+ }
+ setRerenderNumber(n => n + 1);
+ }, [interpreter]);
- 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);
+ useEffect(() => {
+ if (running) {
+ if (speed === 0) {
+ return;
}
- }, [running, nextHandler, speed]);
+ const interval = setInterval(() => {
+ nextHandler();
+ }, 1000 / (speed));
+
+ return () => clearInterval(interval);
+ }
+ }, [running, nextHandler, speed]);
- return (
-
- {running && interpreter && <>
+ return (
+
+ {
+ running && interpreter && <>
>
- }
-
-
-
-
-
- {
- running &&
- <>
-
-
- setSpeed(+e.target.value)}/>
- {speed}
-
- >
- }
+ }
+
+
+
+
- );
- }
-;
+ {
+ running && <>
+
+
+ setSpeed(+e.target.value)}/>
+ {speed}
+
+ >
+ }
+ {
+ error && Error: '{error}'
+ }
+
+ );
+};
export default Runner;
\ No newline at end of file