#!/usr/bin/env python

# Gumby - A simple brainfuck interpreter in Python.
#  By Enrique Sedano.
#  Contact: enrique@esedano.es
#  Version: 0.2 - Base instruction set complete.
#
# This software is distributed under The MIT License (MIT)
#
# Copyright (c) 2014 Enrique Sedano
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

import os
import sys
import argparse
import itertools

class byte:
  value = 0
  def increment(self):
    if self.value < 255: self.value += 1
  def decrement(self):
    if self.value >   0: self.value -= 1
  def printbyte(self):
    sys.stdout.write(str(unichr(self.value)))
  def storebyte(self,val):
    if val is '':
      self.value = 0
    else:
      self.value = ord(str(val).rstrip())

parser = argparse.ArgumentParser()
parser.add_argument('source', type=str, help='Path to the file.')
args = parser.parse_args()

source_file = os.path.abspath(args.source)

f = open(source_file)
s = [x for x in itertools.chain.from_iterable(f.readlines()) if x in ['>','<','+','-','.',',','[',']']]
f.close()

m = [byte()]

sp = 0
mp = 0
while sp < len(s):
  if s[sp] == '>':
    mp += 1
    if mp == len(m): m.append(byte())
    sp += 1
  elif s[sp] == '<':
    if mp > 0: mp -= 1
    sp += 1
  elif s[sp] == '+':
    m[mp].increment()
    sp += 1 
  elif s[sp] == '-':
    m[mp].decrement()
    sp += 1
  elif s[sp] == '.':
    m[mp].printbyte()
    sp += 1
  elif s[sp] == ',':
    b = raw_input()
    while len(b) > 1:
      print 'Input is too long. Please enter a 1-char value only.'
      b = raw_input()
    m[mp].storebyte(b)
    sp += 1
  elif s[sp] == '[':
    if m[mp].value == 0:
      openings = 1
      while openings > 0:
        sp += 1
        if s[sp] == '[': openings += 1
        if s[sp] == ']': openings -= 1
        if sp == len(s):
          sys.exit("Unbalanced [")
    sp += 1
  elif s[sp] == ']':
    if m[mp].value != 0:
      closings = 1
      while closings > 0:
        sp -= 1
        if s[sp] == '[': closings -= 1
        if s[sp] == ']': closings += 1
        if sp < 0:
          sys.exit("Unbalanced ]")
    sp += 1
