Last active
April 8, 2018 06:53
-
-
Save JustinSDK/7a24cb25f70816d4be1ae2cb0ab0f23b to your computer and use it in GitHub Desktop.
Brankfuck - Hello,World
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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