Brainfuck interpreter

Brainfuck is a really easy language without no real purpose despite the fact it's turing complete. This challenge was a coding kata on Codewars. Please note referral url!

As a training exercise it is quite nice because it can be done in a very short period of time. One has to control flow with brackets so must keep track of them and overall fun to experiment in parser area.

The most difficult thing for me was to trace a bug which was inside brackets controller(loops). My handler extracted wrong brackets and the whole program misbehaved. How? Well when brackets are like [..[..[..]]] it is all good but when they are like [..[..]..[..]..] it is bad because I was matching opening brackets, closing brackets then reversed closing brackets and zipped both arrays together. Wrong way! The correct way is to keep track of current depth which I did by simply pushing opening bracket onto array and then poping it when closing bracket was found.

I maybe left one thing bad in this code - preallocated memory and initialized as 0. Preallocated memory is OK but preallocated zeroes are bad because at the end, the result is like 1,2,3,4,0,0,0...0,0 so I must filter that out. This thing is really easy to fix by simply avoiding preinitialization and checking for undefined in + and - controllers.

Also in the last few days I was reading Clean Code and made it a goal for my source code to be as readable as possible.

function brainLuck(code, input) {  
  var size = 512;       // size shows how much memory is preallocated for the program
  var limit = 100000;   // short-circuit on infinite loop

  // preallocate memory and initialize all with 0
  var pointer = size / 2;
  var data = new Array(size);
  for (var i = 0; i < data.length; i++) data[i] = 0;
  var output = [];    

  // instruction pointer
  var ip = 0;

  // loop_pairs will be "double-linked" list. Starting of a bracket will point to closing of it and vice-versa
  var loop_pairs = [];

  var opening_brackets = [];
  var closing_brackets = [];

  code.split('').forEach(function(char, idx) {
    if (char == '[') {      
      opening_brackets.push(idx);
    } else if (char == ']') {      
      var opening_bracket = opening_brackets.pop();
      loop_pairs[idx] = opening_bracket;
      loop_pairs[opening_bracket] = idx;
    }
  });

  // process commands
  var iteration = 0;
  while (ip < code.length) {
    iteration++;
    if (iteration >= limit) break;
    var opcode = code[ip];

    if (opcode == '[') { // loop start
      if (data[pointer] == 0) {
        ip = loop_pairs[ip];        
        continue;
      }
    } else if (opcode == ']') { // loop end
      if (data[pointer] != 0) {        
        ip = loop_pairs[ip];        
        continue;
      }
    }
    else if (opcode == '>') { pointer++ }
    else if (opcode == '<') { pointer-- }    
    else if (opcode == '+') { data[pointer]++; if (data[pointer] > 255) data[pointer] = 0; }
    else if (opcode == '-') { data[pointer]--; if (data[pointer] < 0) data[pointer] = 255; }

    else if (opcode == '.') {
      output.push(data[pointer]); 
    } else if (opcode == ',') { // handle input
      if (input.length == 0) {
        data[pointer] = '';
      } else {        
        // slice the first char of input and grab it's ascii code
        data[pointer] = input[0].charCodeAt(0);
        input = input.substring(1);
      }
    }        
    ip++; 
  }

  // glue the results back. Filter for non-zero values because of preallocated memory containing 0
  return output.filter(function(i) { return i > 0 }).map(function(i) { return String.fromCharCode(i) }).join('');
}

Javascript brainfuck interpreter ready!