--[[
Filename: bf.lua
License: MIT

Copyright (c) 2013 Odd Strabo <oddstr13@openshell.no>

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.
]]

local arr  = {0}
local size = 1
local ptr  = 1

local function ptr_r()
  if size == ptr then
    table.insert(arr, 0)
    size = size + 1
  end
  ptr = ptr + 1
end

local function ptr_l()
  if ptr ~= 1 then
    ptr = ptr - 1
  end
end

local function inc()
  if arr[ptr] ~= 255 then
    arr[ptr] = arr[ptr] + 1
  else
    arr[ptr] = 0
  end
end

local function dec()
  if arr[ptr] ~= 0 then
    arr[ptr] = arr[ptr] - 1
  else
    arr[ptr] = 255
  end
end

local function output()
  write(string.char(arr[ptr]))
end

local function input()
  local continue = true
  while continue do
    local e,v = os.pullEvent()
    if e == "char" then
      arr[ptr] = string.byte(v)
      continue = false
    elseif e == "key" then
      if v == 28 then
        arr[ptr] = 10
        continue = false
      end
    end
  end
end

local function interpet(program)
  ptr = 1
  size = 1
  arr = {0}
  
  local sl = program:len()
  local i = 1
  while i <= sl do
    local ch = program:sub(i,i)
    --write(ch)
    --debugprint(ch)
    local ip = true
    if ch == '>' then
      ptr_r()
    elseif ch == '<' then
      ptr_l()
    elseif ch == '+' then
      inc()
    elseif ch == '-' then
      dec()
    elseif ch == '.' then
      output()
    elseif ch == ',' then
      input()
    elseif ch == '[' then
      if arr[ptr] == 0 then
        local j = i
        local jcont = true
        while jcont do
          j = j + 1
          local jc = program:sub(j,j)
          --debugprint(ch,jc,j)
          if jc == ']' then
            jcont = false
            i = j
          end
        end
      end
    elseif ch == ']' then
      if arr[ptr] ~= 0 then
        local j = i
        local jcont = true
        while jcont do
          j = j - 1
          local jc = program:sub(j,j)
          --debugprint(ch,jc,j)
          if jc == '[' then
            jcont = false
            i = j
          end
        end
      end
    end
    i = i + 1
  end
end

local argv = {...}
if #argv > 0 then
  for k,v in pairs(argv) do
    if fs.exists(v) then
      if fs.isDir(v) then
        print("'"..v.."' is a directory.")
      else
        local fh = fs.open(v, "r")
        local program = fh.readAll()
        fh.close()
        interpet(program)
      end
    else
      print("'"..v.."' no such file.")
    end
  end
else
  print("Brainfuck interpeter.")
  print("Enter exit to exit.")
  local hist = {}
  local continue = true
  while continue do
    write("bf> ")
    local program = read(nil, hist)
    table.insert(hist, program)
    if program == "exit" then
      continue = false
    else
      interpet(program)
      if term.getCursorPos() ~= 0 then
        print()
      end
--      for k,v in pairs(arr) do -- debug, yay
--        debugprint(k, v)
--      end
--      print()
    end
  end
end
