Skip to content

Instantly share code, notes, and snippets.

@JustinSDK
Last active April 8, 2018 06:53
Show Gist options
  • Save JustinSDK/7a24cb25f70816d4be1ae2cb0ab0f23b to your computer and use it in GitHub Desktop.
Save JustinSDK/7a24cb25f70816d4be1ae2cb0ab0f23b to your computer and use it in GitHub Desktop.
Brankfuck - Hello,World
class List {
constructor(array) {
this.array = array;
}
get first() {
return this.array[0];
}
get tail() {
return new List(this.array.slice(1));
}
get init() {
return new List(this.array.slice(0, -1));
}
get last() {
return this.array[this.array.length - 1] ;
}
prepend(elem) {
return new List([elem].concat(this.array));
}
append(elem) {
return new List(this.array.concat([elem]));
}
toString() {
return this.array.join(' ');
}
}
class Head {
constructor(left, current, right) {
this.left = left;
this.current = current;
this.right = right;
}
moveLeft() {
return new Head(
this.left.init,
this.left.last || 0,
this.right.prepend(this.current)
);
}
moveRight() {
return new Head(
this.left.append(this.current),
this.right.first || 0,
this.right.tail
);
}
toString() {
let l = this.left.toString();
let r = this.right.toString();
return `[${l}](${this.current})[${r}]`;
}
}
class Commands {
constructor(commands, idx = 0) {
this.commands = commands;
this.idx = idx;
}
get current() {
return this.commands[this.idx];
}
step() {
return new Commands(this.commands, this.idx + 1);
}
rightBracket() {
function rightB(n, i) {
if(n === 0) {
return i - 1;
}
if(cmds[i] === '[') {
return rightB(n + 1, i + 1);
}
if(cmds[i] === ']') {
return rightB(n - 1, i + 1);
}
return rightB(n, i + 1);
}
return new Commands(this.commands, rightB(1, this.idx + 1));
}
leftBracket() {
let cmds = this.commands;
function leftB(n, i) {
if(n === 0) {
return i + 1;
}
if(cmds[i] === ']') {
return leftB(n + 1, i - 1);
}
if(cmds[i] === '[') {
return leftB(n - 1, i - 1);
}
return leftB(n, i - 1);
}
return new Commands(this.commands, leftB(1, this.idx - 1));
}
isRunnable() {
return this.idx < this.commands.length;
}
}
class Context {
constructor(commands, head) {
this.commands = commands;
this.head = head;
}
isRunnable() {
return this.commands.isRunnable();
}
get data() {
let larr = this.head.left.array;
let carr = [this.head.current];
let rarr = this.head.right.array;
return larr.concat(carr).concat(rarr);
}
}
const fs = require('fs');
function getCharSync(tips = '> ') {
process.stdout.write(tips);
process.stdin.pause();
const buf = Buffer.allocUnsafe(10000);
let response = fs.readSync(process.stdin.fd, buf, 0, 10000, 0);
process.stdin.end();
return buf.toString('utf8', 0, response)[0];
}
class Manual {
constructor() {
this.rules = new Map([
['+', addOne],
['-', minusOne],
['>', moveHeadRight],
['<', moveHeadLeft],
['[', leftBracket],
[']', rightBracket],
['.', putChar],
[',', getChar]
]);
function head(context) {
return context.head.current;
}
function writeCurrent(context, x) {
return new Context(
context.commands.step(),
new Head(context.head.left, x, context.head.right)
);
}
// +
function addOne(context) {
return writeCurrent(context, head(context) + 1);
}
// -
function minusOne(context) {
return writeCurrent(context, head(context) - 1);
}
// <
function moveHeadLeft(context) {
return new Context(
context.commands.step(),
context.head.moveLeft()
);
}
// >
function moveHeadRight(context) {
return new Context(
context.commands.step(),
context.head.moveRight()
);
}
// .
function putChar(context) {
process.stdout.write(String.fromCharCode(head(context)));
return new Context(
context.commands.step(),
context.head
);
}
// ,
function getChar(context) {
let char = getCharSync();
return writeCurrent(context, char.charCodeAt(0));
}
// [
function leftBracket(context) {
return new Context(
head(context) === 0 ? context.commands.rightBracket() : context.commands.step(),
context.head
);
}
// ]
function rightBracket(context) {
return new Context(
head(context) === 0 ? context.commands.step() : context.commands.leftBracket(),
context.head
);
}
}
next_context(context) {
return this.rules.get(context.commands.current)(context);
}
}
class Brainfuck {
constructor(code) {
this.context = new Context(
new Commands(Array.from(code)),
new Head(new List([]), 0, new List([]))
);
this.manual = new Manual();
}
execute() {
return this.runUntilHalt(this.context).data;
}
runUntilHalt(context) {
return context.isRunnable() ?
this.runUntilHalt(this.manual.next_context(context)) :
context;
}
}
let code = '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.';
new Brainfuck(code).execute(); // Hello World!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment