include "parser/variable_helper"
include "parser/invoke_helper"
include "parser/string_helper"
include "parser/function_helper"
include "parser/binop_helper"

h = object.new
h.squish variable_helper
h.squish invoke_helper
h.squish string_helper
h.squish function_helper
h.squish binop_helper

h.compile = {
  "#{file_header}
  _exports = {}
  local _main = function()
    #{method_header}

    setfenv(1, {})

    #{inner_brat}
  end

  local _result = coxpcall(_main, exception._handler)
  if not _lib then
    if not _result then
      os.exit(-1)
    else
      os.exit(0)
    end
  end
  "
}

h.file_header = "
  require \"coxpcall\"
  local _lib
  if package.loaded.core then
    _lib = true
  else
    _lib = false
    require \"core\"
  end
  "

h.method_header = "
  local object = object
  local array = array
  local number = number
  local string = base_string
  local symbol = symbol
  local exception = exception
  local hash = hash
  local regex = regex
  local _self = object
  local _type = type
  local _error = error
  local _tostring = tostring
  local brat_function = brat_function
  local _lifted_call = _lifted_call
  local _rawget = rawget
  local _table = table
  local _lifted = {}
  "

h.interactive = {
  out = inner_brat
  out << "\nreturn #{my.results.last.var}"
}

result = object.new
result.init = { var = null, extras = [:] |
  my.var = var
  my.out = ''
  my.extras = extras
}

result.prototype.get = { v |
  my.extras[v]
}

result.prototype.set = { k, v |
  my.extras[k] = v
}

h.set_result = { var = null, initial = null, extras = [:] |
  res = result.new var, extras

  null? res.var
    { res.var = my.env.next_unset }

  null? res.var
    {
      res.var = my.env.next_var
      res.out = true? initial
              { "\nlocal #{res.var} = #{initial}\n" }
              { "\nlocal #{res.var}\n" }
    }
    {
      true? initial
        { res.out = "\n#{res.var} = #{initial}\n" }
    }

  true? extras[:type]
    { my.env.set_type res.var, extras[:type] }

  res
}

h.r = { result_var, output = null, extras = [:] |
  res = result.new result_var, extras
  res.out = output
  true? extras[:type]
    { my.env.set_type res.var, extras[:type] }
  res
}

export h, :compiler_helper