BrainCurses/implementation.js

From Esolang
Jump to navigation Jump to search
Back to BrainCurses

This is an implementation of BrainCurses in node.js, written by User:Conor O'Brien.

Implementation

Remember to npm install readwrite before running.

const rw = require("readwrite");

class Dequeue extends Array {
    pop(){
        if(this.length === 0) return 0;
        return super.pop();
    }
    
    get top(){
        let v = this.pop();
        this.push(v);
        return v;
    }
    
    set top(v){
        return this[this.length - 1] = v;
    }
    
    inject(value){
        return this.unshift(value);
    }
    
    eject(){
        return this.shift();
    }
}

class BrainCurses {
    constructor(program){
        this.code = program.match(/'.|\[\$|./g);
        this.A = 0;
        this.Dequeue = new Dequeue();
        this.instructions = new Map([
            ["!", () => this.Dequeue.push(this.A)],
            ["@", () => this.A = this.Dequeue.pop()],
            ["^", () => this.Dequeue.inject(this.Dequeue.pop())],
            ["#", () => this.Dequeue.push(this.Dequeue.eject())],
            ["+", () => this.A++],
            ["-", () => this.A--],
            [":", (output, input) => output(this.A)],
            [";", (output, input) => this.A = input()],
            ["%", () => [this.A, this.Dequeue.top] = [this.Dequeue.top, this.A]],
            ["*", () => this.Dequeue.top = this.A],
            ["&", () => this.A = this.Dequeue.top],
            ["[", () => {
                if(this.A !== 0) return;
                let i, depth;
                for(i = this.index + 1, depth = 1; depth && i < this.code.length; i++){
                    if(this.code[i][0] === "[") depth++;
                    else if(this.code[i] === "]") depth--;
                }
                this.index = i - 1;
            }],
            ["[$", () => {
                if(this.Dequeue.top !== 0) return;
                let i, depth;
                for(i = this.index + 1, depth = 1; depth && i < this.code.length; i++){
                    if(this.code[i][0] === "[") depth++;
                    else if(this.code[i] === "]") depth--;
                }
                this.index = i - 1;
            }],
            ["]", () => {
                let i, depth;
                for(i = this.index - 1, depth = 1; depth && i >= 0; --i){
                    if(this.code[i][0] === "[") depth--;
                    else if(this.code[i] === "]") depth++;
                }
                this.index = i;
            }],
            ["_", (output, input) => output(String.fromCharCode(this.A))]
        ]);
    }
    
    execute(output, input){
        for(this.index = 0; this.index < this.code.length; this.index++){
            let cmd = this.code[this.index];
            // console.log(cmd, this.Dequeue);
            if(this.instructions.has(cmd)){
                this.instructions.get(cmd)(output, input);
            } else if(cmd[0] === "'"){
                this.A = cmd.charCodeAt(1);
            }
        }
        return this;
    }
    
    static eval(code, input){
        let iar = input.reduce((p,c)=>p.concat(...c),[]).map(e => e.charCodeAt());
        let BCinst = new BrainCurses(code);
        return BCinst.execute(rw.log, () => iar.length && iar.shift());
    }
}

let args = process.argv.slice(2);

let debug = false;

if(args[0] === "-d" || args[0] === "/d"){
    debug = true;
    args.shift();
}

let res = BrainCurses.eval(rw.read(args.shift()), args);

if(debug) console.log(res.Dequeue);

Usage

node BrainCurses.js <filename> <input>

or

node BrainCurses.js /d <filename> <input>

or

node BrainCurses.js -d <filename> <input>

The latter two print the contents of the dequeue at program termination.

Assumptions

  1. : outputs A as a number;
  2. input reads from left to right

Notices

The string reversal example given on the page ([;!]#[$@_#]) seems to be incorrect, at least, as per this implementation; the correct way of doing it would be this:

;[!;][$@_]