#Nilac is the official Nila compiler. It compiles Nila into pure Javascript. Nilac is currently
#written in Ruby but will be self hosted in the upcoming years.

#Nila and Nilac are being crafted by Adhithya Rajasekaran and Sri Madhavi Rajasekaran

require 'slop'
require 'fileutils'


def compile(input_file_path, *output_file_name)

  def read_file_line_by_line(input_path)

    file_id = open(input_path)

    file_line_by_line = file_id.readlines()

    file_id.close

    return file_line_by_line

  end

  def extract_parsable_file(input_file_contents)

    reversed_file_contents = input_file_contents.reverse

    line_counter = 0

    if input_file_contents.join.include?("__END__")

      while !reversed_file_contents[line_counter].strip.include?("__END__")

        line_counter += 1

      end

      return_contents = input_file_contents[0...-1*line_counter-1]

    else

      input_file_contents

    end

  end

  def replace_multiline_comments(input_file_contents, nila_file_path, *output_js_file_path)

    #This method will replace both the single and multiline comments
    #
    #Single line comment will be replaced by => --single_line_comment[n]
    #
    #Multiline comment will be replaced by => --multiline_comment[n]

    def find_all_matching_indices(input_string, pattern)

      locations = []

      index = input_string.index(pattern)

      while index != nil

        locations << index

        index = input_string.index(pattern, index+1)


      end

      return locations


    end

    def find_file_path(input_path, file_extension)

      extension_remover = input_path.split(file_extension)

      remaining_string = extension_remover[0].reverse

      path_finder = remaining_string.index("/")

      remaining_string = remaining_string.reverse

      return remaining_string[0...remaining_string.length-path_finder]

    end

    def find_file_name(input_path, file_extension)

      extension_remover = input_path.split(file_extension)

      remaining_string = extension_remover[0].reverse

      path_finder = remaining_string.index("/")

      remaining_string = remaining_string.reverse

      return remaining_string[remaining_string.length-path_finder..-1]

    end

    multiline_comments = []

    file_contents_as_string = input_file_contents.join

    modified_file_contents = file_contents_as_string.dup

    multiline_comment_counter = 1

    multiline_comments_start = find_all_matching_indices(file_contents_as_string, "=begin")

    multiline_comments_end = find_all_matching_indices(file_contents_as_string, "=end")

    for y in 0...multiline_comments_start.length

      start_of_multiline_comment = multiline_comments_start[y]

      end_of_multiline_comment = multiline_comments_end[y]

      multiline_comment = file_contents_as_string[start_of_multiline_comment..end_of_multiline_comment+3]

      modified_file_contents = modified_file_contents.gsub(multiline_comment, "--multiline_comment[#{multiline_comment_counter}]\n\n")

      multiline_comment_counter += 1

      multiline_comments << multiline_comment


    end

    temporary_nila_file = find_file_path(nila_file_path, ".nila") + "temp_nila.nila"

    if output_js_file_path.empty?

      output_js_file = find_file_path(nila_file_path, ".nila") + find_file_name(nila_file_path, ".nila") + ".js"

    else

      output_js_file = output_js_file_path[0]

    end

    file_id = open(temporary_nila_file, 'w')

    file_id2 = open(output_js_file, 'w')

    file_id.write(modified_file_contents)

    file_id.close()

    file_id2.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    comments = multiline_comments.dup

    return line_by_line_contents, comments, temporary_nila_file, output_js_file

  end

  def split_semicolon_seperated_expressions(input_file_contents)

    modified_file_contents = input_file_contents.dup

    input_file_contents.each_with_index do |line, index|

      if line.include?("\"")

        first_index = line.index("\"")

        modified_line = line.sub(line[first_index..line.index("\"", first_index+1)], "--string")

      elsif line.include?("'")

        first_index = line.index("'")

        modified_line = line.sub(line[first_index..line.index("'", first_index+1)], "--string")

      else

        modified_line = line

      end

      if modified_line.include?(";")

        replacement_line = modified_file_contents[index]

        replacement_line = replacement_line.split(";").join("\n\n") + "\n"

        modified_file_contents[index] = replacement_line

      end

    end

    return modified_file_contents

  end

  def compile_heredocs(input_file_contents, temporary_nila_file)

    joined_file_contents = input_file_contents.join

    possible_heredocs = input_file_contents.reject { |element| !element.include?("<<-") }

    possible_heredocs = possible_heredocs.collect { |element| element.match(/<<-(.*|\w*)/).to_a[0] }

    possible_heredocs.each do |heredoc|

      delimiter = heredoc[3..-1]

      quote = 2

      if delimiter.include?("'")

        quote = 1

      end

      delimiter = delimiter.gsub("\"", "") if quote == 2

      delimiter = delimiter.gsub("'", "") if quote == 1

      string_split = joined_file_contents.split(heredoc, 2)

      string_extract = string_split[1]

      heredoc_extract = string_extract[0...string_extract.index(delimiter)]

      replacement_string = ""

      if quote == 1

        replacement_string = "'#{heredoc_extract.delete("\"")}'".lstrip.inspect

        replacement_string = replacement_string[1..-2]

      elsif quote == 2

        replacement_string = heredoc_extract.lstrip.inspect

      end

      joined_file_contents = joined_file_contents.sub(heredoc + heredoc_extract + delimiter, replacement_string)

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(joined_file_contents)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    return line_by_line_contents


  end

  def compile_interpolated_strings(input_file_contents)

    def find_all_matching_indices(input_string, pattern)

      locations = []

      index = input_string.index(pattern)

      while index != nil

        locations << index

        index = input_string.index(pattern, index+1)


      end

      return locations


    end

    modified_file_contents = input_file_contents.dup

    single_quoted_strings = input_file_contents.reject { |element| !(element.count("'") >= 2) }

    single_quoted_strings.each do |str|

      modified_string = str.dup

      while modified_string.include?("'")

        first_index = modified_string.index("'")

        string_extract = modified_string[first_index..modified_string.index("'", first_index+1)]

        modified_string = modified_string.sub(string_extract, "--single_quoted")

      end

      input_file_contents[input_file_contents.index(str)] = modified_string

    end

    input_file_contents.each_with_index do |line, index|

      if line.include?("\#{")

        modified_line = line.dup

        interpol_starting_loc = find_all_matching_indices(modified_line, "\#{") + [-1]

        interpolated_strings = []

        until interpol_starting_loc.empty?

          interpol_starting_loc[1] = -2 if interpol_starting_loc[1] == -1

          string_extract = modified_line[interpol_starting_loc[0]+1..interpol_starting_loc[1]+1]

          closed_curly_brace_index = find_all_matching_indices(string_extract, "}")

          index_counter = 0

          test_string = ""

          until closed_curly_brace_index.empty?

            test_string = string_extract[0..closed_curly_brace_index[0]]

            original_string = test_string.dup

            if test_string.include?("{")

              test_string = test_string.reverse.sub("{", "$#{index_counter}$").reverse

              test_string[-1] = "@#{index_counter}@"

            end

            string_extract = string_extract.sub(original_string, test_string)

            closed_curly_brace_index = find_all_matching_indices(string_extract, "}")

            index_counter += 1

          end

          string_extract = string_extract[0..string_extract.length-string_extract.reverse.index(/@\d@/)]

          interpolated_string = "\#{" + string_extract.split("@#{index_counter-1}@")[0].split("$#{index_counter-1}$")[1] + "}"

          to_be_replaced = interpolated_string.scan(/\$\d\$/)

          closing_brace_rep = interpolated_string.scan(/@\d@/)

          to_be_replaced.each_with_index do |rep, index|

            interpolated_string = interpolated_string.sub(rep, "{").sub(closing_brace_rep[index], "}")

          end

          interpolated_strings << interpolated_string

          modified_line = modified_line.sub(interpolated_string, "--interpolate")

          if find_all_matching_indices(modified_line, "\#{").empty?

            interpol_starting_loc = []

          else

            interpol_starting_loc = find_all_matching_indices(modified_line, "\#{") + [-1]

          end

        end

        interpolated_strings.each do |interpol|

          string_split = line.split(interpol)

          if string_split[1].eql?("\"\n")

            replacement_string = "\" + " + interpol[2...-1]

            modified_file_contents[index] = modified_file_contents[index].sub(interpol+"\"", replacement_string)

          elsif string_split[1].eql?("\")\n")

            replacement_string = "\" + " + interpol[2...-1]

            modified_file_contents[index] = modified_file_contents[index].sub(interpol+"\"", replacement_string)

          else

            replacement_string = "\" + " + interpol[2...-1] + " + \""

            modified_file_contents[index] = modified_file_contents[index].sub(interpol, replacement_string)

          end

        end

      end

    end

    return modified_file_contents

  end

  def replace_singleline_comments(input_file_contents)

    single_line_comments = []

    singleline_comment_counter = 1

    for x in 0...input_file_contents.length

      current_row = input_file_contents[x]

      if current_row.include?("#")

        comment_start = current_row.index("#")

        if current_row[comment_start+1] != "{"

          comment = current_row[comment_start..-1]

          single_line_comments << comment

          current_row = current_row.gsub(comment, "--single_line_comment[#{singleline_comment_counter}]\n\n")

          singleline_comment_counter += 1

        end

      end

      input_file_contents[x] = current_row

    end

    return input_file_contents, single_line_comments

  end

  def replace_named_functions(nila_file_contents, temporary_nila_file)

    def extract_array(input_array, start_index, end_index)

      return input_array[start_index..end_index]

    end

    end_locations = []

    key_word_locations = []

    start_blocks = []

    end_blocks = []

    nila_regexp = /(def )/

    named_code_blocks = []

    for x in 0...nila_file_contents.length

      current_row = nila_file_contents[x]

      if current_row.index(nila_regexp) != nil

        key_word_locations << x

      elsif current_row.lstrip.include?("end\n") || current_row.include?("end")

        end_locations << x


      end


    end

    unless key_word_locations.empty?

      modified_file_contents = nila_file_contents.dup

      for y in 0...end_locations.length

        current_location = end_locations[y]

        current_string = modified_file_contents[current_location]

        finder_location = current_location

        begin

          while current_string.index(nila_regexp) == nil

            finder_location -= 1

            current_string = modified_file_contents[finder_location]

          end

          code_block_begin = finder_location

          code_block_end = current_location

          start_blocks << code_block_begin

          end_blocks << code_block_end

          code_block_begin_string_split = modified_file_contents[code_block_begin].split(" ")

          code_block_begin_string_split[0] = code_block_begin_string_split[0].reverse

          code_block_begin_string = code_block_begin_string_split.join(" ")

          modified_file_contents[code_block_begin] = code_block_begin_string

        rescue NoMethodError

          puts "Function compilation failed!"

        end

      end

      final_modified_file_contents = nila_file_contents.dup

      joined_file_contents = final_modified_file_contents.join

      while start_blocks.length != 0

        top_most_level = start_blocks.min

        top_most_level_index = start_blocks.index(top_most_level)

        matching_level = end_blocks[top_most_level_index]

        named_code_blocks << extract_array(final_modified_file_contents, top_most_level, matching_level)

        start_blocks.delete_at(top_most_level_index)

        end_blocks.delete(matching_level)

      end

      codeblock_counter = 1

      named_functions = named_code_blocks.dup

      nested_functions = []

      named_code_blocks.each do |codeblock|

        if joined_file_contents.include?(codeblock.join)

          joined_file_contents = joined_file_contents.sub(codeblock.join, "--named_function[#{codeblock_counter}]\n")

          codeblock_counter += 1

          nested_functions = nested_functions + [[]]

        else

          nested_functions[codeblock_counter-2] << codeblock

          named_functions.delete(codeblock)

        end

      end

    else

      joined_file_contents = nila_file_contents.join

      named_functions = []

      nested_functions = []

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(joined_file_contents)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    return line_by_line_contents, named_functions, nested_functions


  end

  def compile_parallel_assignment(input_file_contents, temporary_nila_file)

    possible_variable_lines = input_file_contents.reject { |element| !element.include? "=" }

    possible_parallel_assignment = possible_variable_lines.reject { |element| !element.split("=")[0].include? "," }

    parallel_assignment_index = []

    possible_parallel_assignment.each do |statement|

      location_array = input_file_contents.each_index.select { |index| input_file_contents[index] == statement }

      parallel_assignment_index << location_array[0]

    end

    modified_file_contents = input_file_contents.dup

    parallel_assignment_counter = 1

    possible_parallel_assignment.each_with_index do |line, index|

      line_split = line.split(" = ")

      right_side_variables = line_split[0].split(",")

      replacement_string = "_ref#{parallel_assignment_counter} = #{line_split[1]}\n\n"

      variable_string = ""

      right_side_variables.each_with_index do |variable, var_index|

        variable_string = variable_string + variable.rstrip + " = _ref#{parallel_assignment_counter}[#{var_index}]\n\n"

      end

      replacement_string = replacement_string + variable_string

      modified_file_contents[parallel_assignment_index[index]] = replacement_string

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(modified_file_contents.join)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    return line_by_line_contents

  end

  def compile_default_values(input_file_contents, temporary_nila_file)

    #This method compiles default values present in functions. An example is provided below

    # def fill(container = "cup",liquid = "coffee")
    #   puts "Filling the #{container} with #{liquid}"
    # end

    def parse_default_values(input_function_definition)

      split1, split2 = input_function_definition.split("(")

      split2, split3 = split2.split(")")

      function_parameters = split2.split(",")

      default_value_parameters = function_parameters.reject { |element| !element.include? "=" }

      replacement_parameters = []

      replacement_string = ""

      default_value_parameters.each do |paramvalue|

        param, value = paramvalue.split("=")

        replacement_parameters << param.lstrip.rstrip

        replacement_string = replacement_string + "\n" + "if (#{param.lstrip.rstrip} == null) {\n  #{paramvalue.lstrip.rstrip}\n}\n" +"\n"

      end

      return replacement_string, default_value_parameters, replacement_parameters

    end

    possible_default_values = input_file_contents.dup.reject { |element| !element.include?("def") }

    possible_default_values = possible_default_values.reject { |element| !element.include?("=") }

    if !possible_default_values.empty?

      possible_default_values.each do |line|

        current_line_index = input_file_contents.each_index.select { |index| input_file_contents[index] == line }.flatten[0]

        replacement_string, value_parameters, replacement_parameters = parse_default_values(line)

        modified_line = line.dup

        value_parameters.each_with_index do |val, index|

          modified_line = modified_line.sub(val, replacement_parameters[index])

        end

        input_file_contents[current_line_index] = modified_line

        input_file_contents[current_line_index + 1] = replacement_string

      end

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(input_file_contents.join)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    return line_by_line_contents

  end

  def get_variables(input_file_contents, temporary_nila_file)

    variables = []

    input_file_contents = input_file_contents.collect { |element| element.gsub("==", "equalequal") }

    input_file_contents = input_file_contents.collect { |element| element.gsub("!=", "notequal") }

    input_file_contents = input_file_contents.collect { |element| element.gsub("+=", "plusequal") }

    input_file_contents = input_file_contents.collect { |element| element.gsub("-=", "minusequal") }

    input_file_contents = input_file_contents.collect { |element| element.gsub("*=", "multiequal") }

    input_file_contents = input_file_contents.collect { |element| element.gsub("/=", "divequal") }

    input_file_contents = input_file_contents.collect { |element| element.gsub("%=", "modequal") }

    input_file_contents = input_file_contents.collect { |element| element.gsub("=~", "matchequal") }

    for x in 0...input_file_contents.length

      current_row = input_file_contents[x]

      if current_row.include?("=") and !current_row.include?("def")

        current_row = current_row.rstrip + "\n"

        current_row_split = current_row.split("=")

        for y in 0...current_row_split.length

          current_row_split[y] = current_row_split[y].strip


        end

        if current_row_split[0].include?("[") or current_row_split[0].include?("(")

          current_row_split[0] = current_row_split[0][0...current_row_split[0].index("[")]

        end

        variables << current_row_split[0]


      end

      input_file_contents[x] = current_row

    end

    file_contents_as_string = input_file_contents.join

    file_id = open(temporary_nila_file, 'w')

    file_id.write(file_contents_as_string)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    if variables.length > 0

      variable_declaration_string = "var " + variables.uniq.sort.join(", ") + "\n\n"

      line_by_line_contents = [variable_declaration_string, line_by_line_contents].flatten

    end

    line_by_line_contents = line_by_line_contents.collect { |element| element.gsub("plusequal", "+=") }

    line_by_line_contents = line_by_line_contents.collect { |element| element.gsub("minusequal", "-=") }

    line_by_line_contents = line_by_line_contents.collect { |element| element.gsub("multiequal", "*=") }

    line_by_line_contents = line_by_line_contents.collect { |element| element.gsub("divequal", "/=") }

    line_by_line_contents = line_by_line_contents.collect { |element| element.gsub("modequal", "%=") }

    line_by_line_contents = line_by_line_contents.collect { |element| element.gsub("equalequal", "==") }

    line_by_line_contents = line_by_line_contents.collect { |element| element.gsub("notequal", "!=") }

    line_by_line_contents = line_by_line_contents.collect { |element| element.gsub("matchequal", "=~") }

    return variables.uniq, line_by_line_contents

  end

  def remove_question_marks(input_file_contents, variable_list, temporary_nila_file)

    #A method to remove question marks from global variable names. Local variables are dealt
    #with in their appropriate scope.

    #Params:
    #input_file_contents => An array containing the contents of the input nila file
    #variable_list => An array containing all the global variables declared in the file
    #temporary_nila_file => A file object used to write temporary contents

    #Example:

    #Nila
    #isprime? = false

    #Javascript Output
    #var isprime;
    #isprime = false;

    #Returns a modified input_file_contents with all the question marks removed

    joined_file_contents = input_file_contents.join

    variable_list.each do |var|

      if var.include? "?"

        joined_file_contents = joined_file_contents.gsub(var, var[0...-1])

      end

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(joined_file_contents)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    return line_by_line_contents

  end

  def compile_arrays(input_file_contents, temporary_nila_file)

    def compile_w_arrays(input_file_contents)

      def extract(input_string, pattern_start, pattern_end)

        def find_all_matching_indices(input_string, pattern)

          locations = []

          index = input_string.index(pattern)

          while index != nil

            locations << index

            index = input_string.index(pattern, index+1)


          end

          return locations


        end

        all_start_locations = find_all_matching_indices(input_string, pattern_start)

        all_end_locations = find_all_matching_indices(input_string, pattern_end)

        pattern = []

        all_start_locations.each_with_index do |location, index|

          pattern << input_string[location..all_end_locations[index]]

        end

        return pattern

      end

      def compile_w_syntax(input_string)

        modified_input_string = input_string[3...-1]

        string_split = modified_input_string.split(" ")

        return string_split.to_s

      end

      modified_file_contents = input_file_contents.dup

      input_file_contents.each_with_index do |line, index|

        if line.include?("%w{")

          string_arrays = extract(line, "%w{", "}")

          string_arrays.each do |array|

            modified_file_contents[index] = modified_file_contents[index].sub(array, compile_w_syntax(array))

          end

        end

      end

      return modified_file_contents

    end

    def compile_array_indexing(input_file_contents)

      possible_indexing_operation = input_file_contents.dup.reject { |element| !element.include? "[" and !element.include? "]" }

      possible_range_indexing = possible_indexing_operation.reject { |element| !element.include? ".." }

      triple_range_indexing = possible_range_indexing.reject { |element| !element.include? "..." }

      triple_range_indexes = []

      triple_range_indexing.each do |line|

        triple_range_indexes << input_file_contents.dup.each_index.select { |index| input_file_contents[index] == line }

      end

      triple_range_indexes = triple_range_indexes.flatten

      triple_range_indexing.each_with_index do |line, index|

        split1, split2 = line.split("[")

        range_index, split3 = split2.split("]")

        index_start, index_end = range_index.split "..."

        replacement_string = nil

        if index_end.strip == "end"

          replacement_string = split1 + ".slice(#{index_start},#{split}.length)\n"

        else

          replacement_string = split1 + ".slice(#{index_start},#{index_end})\n"

        end

        possible_range_indexing.delete(input_file_contents[triple_range_indexes[index]])

        possible_indexing_operation.delete(input_file_contents[triple_range_indexes[index]])

        input_file_contents[triple_range_indexes[index]] = replacement_string

      end

      double_range_indexing = possible_range_indexing.reject { |element| !element.include?("..") }

      double_range_indexes = []

      double_range_indexing.each do |line|

        double_range_indexes << input_file_contents.dup.each_index.select { |index| input_file_contents[index] == line }

      end

      double_range_indexes = double_range_indexes.flatten

      double_range_indexing.each_with_index do |line, index|

        split1, split2 = line.split("[")

        range_index, split3 = split2.split("]")

        index_start, index_end = range_index.split ".."

        index_start = "" if index_start.nil?

        index_end = "" if index_end.nil?

        replacement_string = nil

        if index_end.strip == "end"

          replacement_string = split1 + ".slice(#{index_start})\n"

        elsif index_end.strip == "" and index_start.strip == ""

          replacement_string = split1 + ".slice(0)\n"

        else

          replacement_string = split1 + ".slice(#{index_start},#{index_end}+1)\n"

        end

        possible_range_indexing.delete(input_file_contents[double_range_indexes[index]])

        possible_indexing_operation.delete(input_file_contents[double_range_indexes[index]])

        input_file_contents[double_range_indexes[index]] = replacement_string

      end

      duplicating_operations = input_file_contents.dup.reject { |element| !element.include?(".dup") }

      duplicating_operation_indexes = []

      duplicating_operations.each do |line|

        duplicating_operation_indexes << input_file_contents.dup.each_index.select { |index| input_file_contents[index] == line }

      end

      duplicating_operation_indexes = duplicating_operation_indexes.flatten

      duplicating_operation_indexes.each do |index|

        input_file_contents[index] = input_file_contents[index].sub(".dup", ".slice(0)")

      end

      return input_file_contents

    end

    def compile_multiline(input_file_contents, temporary_nila_file)

      possible_arrays = input_file_contents.reject { |element| !element.include?("[") }

      possible_multiline_arrays = possible_arrays.reject { |element| element.include?("]") }

      multiline_arrays = []

      possible_multiline_arrays.each do |starting_line|

        index = input_file_contents.index(starting_line)

        line = starting_line

        until line.include?("]")

          index += 1

          line = input_file_contents[index]

        end

        multiline_arrays << input_file_contents[input_file_contents.index(starting_line)..index]

      end

      joined_file_contents = input_file_contents.join

      multiline_arrays.each do |array|

        modified_array = array.join

        array_extract = modified_array[modified_array.index("[")..modified_array.index("]")]

        array_contents = array_extract.split("[")[1].split("]")[0].lstrip.rstrip.split(",").collect { |element| element.lstrip.rstrip }

        array_contents = "[" + array_contents.join(",") + "]"

        joined_file_contents = joined_file_contents.sub(array_extract, array_contents)

      end

      file_id = open(temporary_nila_file, 'w')

      file_id.write(joined_file_contents)

      file_id.close()

      line_by_line_contents = read_file_line_by_line(temporary_nila_file)

      return line_by_line_contents

    end

    def compile_array_operators(input_file_contents)

      possible_operator_usage = input_file_contents.reject { |element| !element.include?("<<") }

      possible_operator_usage.each do |usage|

        left, right = usage.split("<<")

        input_file_contents[input_file_contents.index(usage)] = left.rstrip + ".push(#{right.lstrip})"

      end

      return input_file_contents

    end

    input_file_contents = compile_w_arrays(input_file_contents)

    input_file_contents = compile_array_indexing(input_file_contents)

    input_file_contents = compile_multiline(input_file_contents, temporary_nila_file)

    input_file_contents = compile_array_operators(input_file_contents)

    return input_file_contents


  end

  def compile_hashes(input_file_contents,temporary_nila_file)

    def compile_multiline_hashes(input_file_contents,temporary_nila_file)

      possible_hashes = input_file_contents.reject { |element| !element.include?("{") }

      possible_multiline_hashes = possible_hashes.reject { |element| element.include?("}") }

      multiline_hashes = []

      possible_multiline_hashes.each do |starting_line|

        index = input_file_contents.index(starting_line)

        line = starting_line

        until line.include?("}")

          index += 1

          line = input_file_contents[index]

        end

        multiline_hashes << input_file_contents[input_file_contents.index(starting_line)..index]

      end

      joined_file_contents = input_file_contents.join

      multiline_hashes.each do |hash|

        modified_hash = hash.join

        hash_extract = modified_hash[modified_hash.index("{")..modified_hash.index("}")]

        hash_contents = hash_extract.split("{")[1].split("}")[0].lstrip.rstrip.split(",").collect { |element| element.lstrip.rstrip }

        hash_contents = "{" + hash_contents.join(",") + "}"

        joined_file_contents = joined_file_contents.sub(hash_extract, hash_contents)

      end

      file_id = open(temporary_nila_file, 'w')

      file_id.write(joined_file_contents)

      file_id.close()

      line_by_line_contents = read_file_line_by_line(temporary_nila_file)

      return line_by_line_contents

    end

    def compile_inline_hashes(input_file_contents)

      modified_file_contents = input_file_contents.clone.collect {|element| element.gsub(/(#|%)\w?\{/,"innerrii0opol115")}

      possible_inline_hashes = modified_file_contents.reject {|element| !element.include?("{")}

      possible_inline_hashes.each do |hash|

        hash_extract = hash[hash.index("{")..hash.index("}")]

        contents = hash_extract[1...-1].split(",")

        hash_contents = []

        contents.each do |items|

          items = items.lstrip.sub(":","") if items.lstrip[0] == ":"

          key, value = items.split("=>").collect {|element| element.lstrip.rstrip} if items.include?("=>")

          key, value = items.split(":").collect {|element| element.lstrip.rstrip} if items.include?(":")

          key = key.gsub("'","").gsub("\"","")

          hash_contents << "  #{key}: #{value},"

        end

        replacement_string = "{\n" + hash_contents.join("\n") + "\n};\n"

        input_file_contents[input_file_contents.index(hash)] = input_file_contents[input_file_contents.index(hash)].sub(hash_extract,replacement_string)

      end

      return input_file_contents

    end

    file_contents = compile_multiline_hashes(input_file_contents,temporary_nila_file)

    file_contents = compile_inline_hashes(file_contents)

    return file_contents

  end

  def compile_strings(input_file_contents)

    def compile_small_q_syntax(input_file_contents)

      possible_syntax_usage = input_file_contents.reject { |element| !element.include?("%q") }

      possible_syntax_usage.each do |line|

        modified_line = line.dup

        line_split = line.split("+").collect { |element| element.lstrip.rstrip }

        line_split.each do |str|

          delimiter = str[str.index("%q")+2]

          string_extract = str[str.index("%q")..-1]

          delimiter = "}" if delimiter.eql?("{")

          delimiter = ")" if delimiter.eql?("(")

          delimiter = ">" if delimiter.eql?("<")

          if string_extract[-1].eql?(delimiter)

            input_file_contents[input_file_contents.index(modified_line)] = input_file_contents[input_file_contents.index(modified_line)].sub(string_extract, "'#{string_extract[3...-1]}'")

            modified_line = modified_line.sub(string_extract, "'#{string_extract[3...-1]}'")

          elsif delimiter.eql?(" ")

            input_file_contents[input_file_contents.index(modified_line)] = input_file_contents[input_file_contents.index(modified_line)].sub(string_extract, "'#{string_extract[3..-1]}'")

            modified_line = modified_line.sub(string_extract, "'#{string_extract[3..-1]}'")

          end

        end

      end

      return input_file_contents

    end

    def compile_big_q_syntax(input_file_contents)

      possible_syntax_usage = input_file_contents.reject { |element| !element.include?("%Q") }

      possible_syntax_usage.each do |line|

        modified_line = line.dup

        line_split = line.split("+").collect { |element| element.lstrip.rstrip }

        line_split.each do |str|

          delimiter = str[str.index("%Q")+2]

          string_extract = str[str.index("%Q")..-1]

          delimiter = "}" if delimiter.eql?("{")

          delimiter = ")" if delimiter.eql?("(")

          delimiter = ">" if delimiter.eql?("<")

          if string_extract[-1].eql?(delimiter)

            input_file_contents[input_file_contents.index(modified_line)] = input_file_contents[input_file_contents.index(modified_line)].sub(string_extract, "\"#{string_extract[3...-1]}\"")

            modified_line = modified_line.sub(string_extract, "\"#{string_extract[3...-1]}\"")

          elsif delimiter.eql?(" ")

            input_file_contents[input_file_contents.index(modified_line)] = input_file_contents[input_file_contents.index(modified_line)].sub(string_extract, "\"#{string_extract[3..-1]}\"")

            modified_line = modified_line.sub(string_extract, "\"#{string_extract[3..-1]}\"")

          end

        end

      end

      return input_file_contents

    end

    def compile_percentage_syntax(input_file_contents)

      possible_syntax_usage = input_file_contents.reject { |element| !element.include?("%") }

      possible_syntax_usage = possible_syntax_usage.reject { |element| element.index(/(\%(\W|\s)\w{1,})/).nil? }

      possible_syntax_usage.each do |line|

        modified_line = line.dup

        line_split = line.split("+").collect { |element| element.lstrip.rstrip }

        line_split.each do |str|

          delimiter = str[str.index("%")+1]

          string_extract = str[str.index("%")..-1]

          delimiter = "}" if delimiter.eql?("{")

          delimiter = ")" if delimiter.eql?("(")

          delimiter = ">" if delimiter.eql?("<")

          if string_extract[-1].eql?(delimiter)

            input_file_contents[input_file_contents.index(modified_line)] = input_file_contents[input_file_contents.index(modified_line)].sub(string_extract, "\"#{string_extract[2...-1]}\"")

            modified_line = modified_line.sub(string_extract, "\"#{string_extract[2...-1]}\"")

          elsif delimiter.eql?(" ")

            input_file_contents[input_file_contents.index(modified_line)] = input_file_contents[input_file_contents.index(modified_line)].sub(string_extract, "\"#{string_extract[2..-1]}\"")

            modified_line = modified_line.sub(string_extract, "\"#{string_extract[2..-1]}\"")

          end

        end

      end

      return input_file_contents

    end

    file_contents = compile_small_q_syntax(input_file_contents)

    file_contents = compile_big_q_syntax(file_contents)

    file_contents = compile_percentage_syntax(file_contents)

    return file_contents

  end

  def compile_named_functions(input_file_contents, named_code_blocks, nested_functions, temporary_nila_file)

    #This method compiles all the named Nila functions. Below is an example of what is meant
    #by named/explicit function

    #def square(input_number)
    #
    #   input_number*input_number
    #
    #end

    #The above function will compile to

    #function square(input_number) {
    #
    #  return input_number*input_number;
    #
    #}

    def is_parameterless?(input_function_block)

      if input_function_block[0].include?("(")

        false

      else

        true

      end

    end

    def lexical_scoped_variables(input_function_block)

      #This method will pickup and declare all the variables inside a function block. In future, this method will be
      #merged with the get variables method

      controlregexp = /(if |while |def |function |function\()/

      variables = []

      function_name, parameters = input_function_block[0].split("(")

      parameters = parameters.split(")")[0].split(",")

      parameters = parameters.collect { |element| element.strip }

      input_function_block.each do |line|

        if line.include? "=" and line.index(controlregexp).nil?

          current_line_split = line.strip.split("=")

          variables << current_line_split[0].rstrip

        end

      end

      parameters.each do |param|

        if variables.include?(param)

          variables.delete(param)

        end

      end

      if variables.empty?

        return []

      else

        return variables.uniq

      end

    end

    def remove_question_marks(input_file_contents, input_list, temporary_nila_file)

      joined_file_contents = input_file_contents.join

      input_list.each do |element|

        if element.include? "?"

          joined_file_contents = joined_file_contents.gsub(element, element[0...-1])

        end

      end

      file_id = open(temporary_nila_file, 'w')

      file_id.write(joined_file_contents)

      file_id.close()

      line_by_line_contents = read_file_line_by_line(temporary_nila_file)

      return line_by_line_contents

    end

    def add_auto_return_statement(input_array)

      joined_array = input_array.join

      reversed_input_array = input_array.reverse

      if !joined_array.include?("return ")

        rejected_array = reversed_input_array.reject { |content| content.lstrip.eql?("") }

        rejected_array = rejected_array[1..-1]

        if !rejected_array[0].strip.eql?("}")

          if !rejected_array[0].strip.eql?("end")

            last_statement = rejected_array[0]

            replacement_string = "return #{last_statement.lstrip}"

            input_array[input_array.index(last_statement)] = replacement_string

          end

        end

      end

      return input_array

    end

    def compile_multiple_return(input_array)

      def find_all_matching_indices(input_string, pattern)

        locations = []

        index = input_string.index(pattern)

        while index != nil

          locations << index

          index = input_string.index(pattern, index+1)


        end

        return locations


      end

      modified_input_array = input_array.dup

      return_statements = input_array.dup.reject { |element| !element.include? "return" }

      multiple_return_statements = return_statements.dup.reject { |element| !element.include? "," }

      modified_multiple_return_statements = multiple_return_statements.dup

      return_statement_index = []

      multiple_return_statements.each do |statement|

        location_array = modified_input_array.each_index.select { |index| modified_input_array[index] == statement }

        return_statement_index << location_array[0]

      end

      multiple_return_statements.each_with_index do |return_statement, index|

        replacement_counter = 0

        if return_statement.include? "\""

          starting_quotes = find_all_matching_indices(return_statement, "\"")

          for x in 0...(starting_quotes.length)/2

            quotes = return_statement[starting_quotes[x]..starting_quotes[x+1]]

            replacement_counter += 1

            modified_multiple_return_statements[index] = modified_multiple_return_statements[index].sub(quotes, "repstring#{1}")

            modified_input_array[return_statement_index[index]] = modified_multiple_return_statements[index].sub(quotes, "repstring#{1}")

          end

        end

      end

      modified_multiple_return_statements = modified_multiple_return_statements.reject { |element| !element.include? "," }

      return_statement_index = []

      modified_multiple_return_statements.each do |statement|

        location_array = modified_input_array.each_index.select { |index| modified_input_array[index] == statement }

        return_statement_index << location_array[0]

      end

      modified_multiple_return_statements.each_with_index do |return_statement, index|

        method_call_counter = 0

        if return_statement.include? "("

          open_paran_location = find_all_matching_indices(return_statement, "(")

          open_paran_location.each do |paran_index|

            method_call = return_statement[paran_index..return_statement.index(")", paran_index+1)]

            method_call_counter += 1

            modified_multiple_return_statements[index] = modified_multiple_return_statements[index].sub(method_call, "methodcall#{method_call_counter}")

            modified_input_array[return_statement_index[index]] = modified_multiple_return_statements[index].sub(method_call, "methodcall#{method_call_counter}")

          end

        end

      end

      modified_multiple_return_statements = modified_multiple_return_statements.reject { |element| !element.include?(",") }

      return_statement_index = []

      modified_multiple_return_statements.each do |statement|

        location_array = modified_input_array.each_index.select { |index| modified_input_array[index] == statement }

        return_statement_index << location_array[0]

      end

      return_statement_index.each do |index|

        original_statement = input_array[index]

        statement_split = original_statement.split("return ")

        replacement_split = "return [" + statement_split[1].rstrip + "]\n\n"

        input_array[index] = replacement_split

      end

      return input_array

    end

    def compile_function(input_array, temporary_nila_file)

      modified_input_array = input_array.dup

      if is_parameterless?(modified_input_array)

        if modified_input_array[0].include?("--single")

          modified_input_array[0] = input_array[0].sub "def", "function"

          interim_string = modified_input_array[0].split("--single")

          modified_input_array[0] = interim_string[0].rstrip + "() {\n--single" + interim_string[1]


        elsif modified_input_array[0].include?("--multi")

          modified_input_array[0] = input_array[0].sub "def", "function"

          interim_string = modified_input_array[0].split("--multi")

          modified_input_array[0] = interim_string[0].rstrip + "() {\n--multi" + interim_string[1]

        else

          modified_input_array[0] = input_array[0].sub "def", "function"

          modified_input_array[0] = modified_input_array[0].rstrip + "() {\n"

        end

      else

        if modified_input_array[0].include?("--single")

          modified_input_array[0] = input_array[0].sub "def", "function"

          interim_string = modified_input_array[0].split("--single")

          modified_input_array[0] = interim_string[0].rstrip + " {\n--single" + interim_string[1]


        elsif modified_input_array[0].include?("--multi")

          modified_input_array[0] = input_array[0].sub "def", "function"

          interim_string = modified_input_array[0].split("--multi")

          modified_input_array[0] = interim_string[0].rstrip + " {\n--multi" + interim_string[1]

        else

          modified_input_array[0] = input_array[0].sub "def", "function"

          modified_input_array[0] = modified_input_array[0].rstrip + " {\n"

        end

      end

      modified_input_array[-1] = input_array[-1].sub "end", "}\n"

      modified_input_array = compile_parallel_assignment(modified_input_array, temporary_nila_file)

      variables = lexical_scoped_variables(modified_input_array)

      if !variables.empty?

        variable_string = "\nvar " + variables.join(", ") + "\n"

        modified_input_array.insert(1, variable_string)

      end

      modified_input_array = remove_question_marks(modified_input_array, variables, temporary_nila_file)

      modified_input_array = add_auto_return_statement(modified_input_array)

      modified_input_array = compile_multiple_return(modified_input_array)

      return modified_input_array

    end

    def extract_function_name(input_code_block)

      first_line = input_code_block[0]

      first_line_split = first_line.split(" ")

      if first_line_split[1].include?("(")

        function_name, parameters = first_line_split[1].split("(")

      else

        function_name = first_line_split[1]

      end

      return function_name

    end

    joined_file_contents = input_file_contents.join

    unless named_code_blocks.empty?

      codeblock_counter = 1

      function_names = []

      named_code_blocks.each do |codeblock|

        function_names[codeblock_counter-1] = []

        joined_file_contents = joined_file_contents.sub("--named_function[#{codeblock_counter}]\n", compile_function(codeblock, temporary_nila_file).join)

        codeblock_counter += 1

        current_nested_functions = nested_functions[codeblock_counter-2]

        function_names[codeblock_counter-2] << extract_function_name(codeblock)

        current_nested_functions.each do |nested_function|

          function_names[codeblock_counter-2] << extract_function_name(nested_function)

          joined_file_contents = joined_file_contents.sub(nested_function.join, compile_function(nested_function, temporary_nila_file).join)

        end

      end

    else

      function_names = []

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(joined_file_contents)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    return line_by_line_contents, function_names

  end

  def compile_custom_function_map(input_file_contents)

    function_map_replacements = {

        "puts" => "console.log",

        "p" => "console.log",

        "print" => "process.stdout.write"
    }

    function_map = function_map_replacements.keys

    modified_file_contents = input_file_contents.dup

    input_file_contents.each_with_index do |line, index|

      function_map.each do |function|

        if line.include?(function+"(") or line.include?(function+" ")

          modified_file_contents[index] = line.sub(function, function_map_replacements[function])

        end

      end

    end

    return modified_file_contents, function_map_replacements.values

  end

  def compile_whitespace_delimited_functions(input_file_contents, function_names, temporary_nila_file)

    def extract(input_string, pattern_start, pattern_end)

      def find_all_matching_indices(input_string, pattern)

        locations = []

        index = input_string.index(pattern)

        while index != nil

          locations << index

          index = input_string.index(pattern, index+1)


        end

        return locations


      end

      all_start_locations = find_all_matching_indices(input_string, pattern_start)

      pattern = []

      all_start_locations.each do |location|

        extracted_string = input_string[location..-1]

        pattern << extracted_string[0..extracted_string.index(pattern_end)]

      end

      return pattern

    end

    begin

      input_file_contents[-1] = input_file_contents[-1] + "\n" if !input_file_contents[-1].include?("\n")

      joined_file_contents = input_file_contents.join

      function_names.each do |list_of_functions|

        list_of_functions.each do |function|

          matching_strings = extract(joined_file_contents, function+" ", "\n")

          matching_strings.each do |string|

            modified_string = string.dup

            modified_string = modified_string.rstrip + modified_string.split(modified_string.rstrip)[1].gsub(" ", "")

            modified_string = modified_string.sub(function+" ", function+"(")

            modified_string = modified_string.sub("\n", ")\n")

            joined_file_contents = joined_file_contents.sub(string, modified_string)

          end

        end

      end

    rescue NoMethodError

      puts "Whitespace delimitation exited with errors!"

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(joined_file_contents)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    return line_by_line_contents

  end

  def compile_conditional_structures(input_file_contents, temporary_nila_file)

    def replace_unless_until(input_file_contents)

      modified_file_contents = input_file_contents.clone

      possible_unless_commands = input_file_contents.reject { |element| !element.include?("unless") }

      unless_commands = possible_unless_commands.reject { |element| !element.lstrip.split("unless")[0].empty? }

      unless_commands.each do |command|

        junk, condition = command.split("unless ")

        condition = condition.gsub(" and "," && ").gsub(" or "," || ").gsub(" not "," !")

        replacement_string = "if !(#{condition.lstrip.rstrip})\n"

        modified_file_contents[modified_file_contents.index(command)] = replacement_string

      end

      possible_until_commands = input_file_contents.reject { |element| !element.include?("until") }

      until_commands = possible_until_commands.reject { |element| !element.lstrip.split("until")[0].empty? }

      until_commands.each do |command|

        junk, condition = command.split("until ")

        condition = condition.gsub(" and "," && ").gsub(" or "," || ").gsub(" not "," !")

        replacement_string = "while !(#{condition.lstrip.rstrip})\n"

        modified_file_contents[modified_file_contents.index(command)] = replacement_string

      end

      return modified_file_contents

    end

    def compile_inline_conditionals(input_file_contents, temporary_nila_file)

      conditionals = [/( if )/, /( while )/, /( unless )/, /( until )/]

      plain_conditionals = [" if ", " while ", " unless ", " until "]

      joined_file_contents = input_file_contents.join

      output_statement = ""

      conditionals.each_with_index do |regex, index|

        matching_lines = input_file_contents.reject { |content| content.index(regex).nil? }

        matching_lines.each do |line|

          line_split = line.split(plain_conditionals[index])

          condition = line_split[1]

          condition = condition.gsub(" and "," && ").gsub(" or "," || ").gsub(" not "," !")

          if index == 0

            output_statement = "if (#{condition.lstrip.rstrip.gsub("?", "")}) {\n\n#{line_split[0]}\n}\n"

          elsif index == 1

            output_statement = "while (#{condition.lstrip.rstrip.gsub("?", "")}) {\n\n#{line_split[0]}\n}\n"

          elsif index == 2

            output_statement = "if (!(#{condition.lstrip.rstrip.gsub("?", "")})) {\n\n#{line_split[0]}\n}\n"

          elsif index == 3

            output_statement = "while (!(#{condition.lstrip.rstrip.gsub("?", "")})) {\n\n#{line_split[0]}\n}\n"

          end

          joined_file_contents = joined_file_contents.sub(line, output_statement)

        end

      end

      file_id = open(temporary_nila_file, 'w')

      file_id.write(joined_file_contents)

      file_id.close()

      line_by_line_contents = read_file_line_by_line(temporary_nila_file)

      return line_by_line_contents

    end

    def compile_regular_if(input_file_contents, temporary_nila_file)

      def convert_string_to_array(input_string, temporary_nila_file)

        file_id = open(temporary_nila_file, 'w')

        file_id.write(input_string)

        file_id.close()

        line_by_line_contents = read_file_line_by_line(temporary_nila_file)

        return line_by_line_contents

      end

      def extract_if_blocks(if_statement_indexes, input_file_contents)

        possible_if_blocks = []

        if_block_counter = 0

        extracted_blocks = []

        controlregexp = /(if |while |def )/

        rejectionregexp = /( if | while )/

        for x in 0...if_statement_indexes.length-1

          possible_if_blocks << input_file_contents[if_statement_indexes[x]..if_statement_indexes[x+1]]

        end

        end_counter = 0

        end_index = []

        current_block = []

        possible_if_blocks.each_with_index do |block|

          current_block += block

          current_block.each_with_index do |line, index|

            if line.strip.eql? "end"

              end_counter += 1

              end_index << index

            end

          end

          if end_counter > 0

            until end_index.empty?

              array_extract = current_block[0..end_index[0]].reverse

              index_counter = 0

              array_extract.each_with_index do |line|

                break if (line.lstrip.index(controlregexp) != nil and line.lstrip.index(rejectionregexp).nil?)

                index_counter += 1

              end

              block_extract = array_extract[0..index_counter].reverse

              extracted_blocks << block_extract

              block_start = current_block.index(block_extract[0])

              block_end = current_block.index(block_extract[-1])

              current_block[block_start..block_end] = "--ifblock#{if_block_counter}"

              if_block_counter += 1

              end_counter = 0

              end_index = []

              current_block.each_with_index do |line, index|

                if line.strip.eql? "end"

                  end_counter += 1

                  end_index << index

                end

              end

            end

          end

        end

        return current_block, extracted_blocks

      end

      def compile_if_syntax(input_block)

        strings = []

        string_counter = 0

        modified_input_block = input_block.dup

        input_block.each_with_index do |line, index|

          if line.include?("\"")

            opening_quotes = line.index("\"")

            string_extract = line[opening_quotes..line.index("\"", opening_quotes+1)]

            strings << string_extract

            modified_input_block[index] = modified_input_block[index].sub(string_extract, "--string{#{string_counter}}")

            string_counter += 1

          end

        end

        input_block = modified_input_block

        starting_line = input_block[0]

        starting_line = starting_line + "\n" if starting_line.lstrip == starting_line

        junk, condition = starting_line.split("if")

        condition = condition.gsub(" and "," && ").gsub(" or "," || ").gsub(" not "," !")

        input_block[0] = "Euuf (#{condition.lstrip.rstrip.gsub("?", "")}) {\n"

        input_block[-1] = input_block[-1].lstrip.sub("end", "}")

        elsif_statements = input_block.reject { |element| !element.include?("elsuf") }

        elsif_statements.each do |statement|

          junk, condition = statement.split("elsuf")

          condition = condition.gsub(" and "," && ").gsub(" or "," || ").gsub(" not "," !")

          input_block[input_block.index(statement)] = "} elsuf (#{condition.lstrip.rstrip.gsub("?", "")}) {\n"

        end

        else_statements = input_block.reject { |element| !element.include?("else") }

        else_statements.each do |statement|

          input_block[input_block.index(statement)] = "} else {\n"

        end

        modified_input_block = input_block.dup

        input_block.each_with_index do |line, index|

          if line.include?("--string{")

            junk, remains = line.split("--string{")

            string_index, junk = remains.split("}")

            modified_input_block[index] = modified_input_block[index].sub("--string{#{string_index.strip}}", strings[string_index.strip.to_i])

          end

        end

        return modified_input_block

      end

      input_file_contents = input_file_contents.collect { |element| element.sub("elsif", "elsuf") }

      possible_if_statements = input_file_contents.reject { |element| !element.include?("if") }

      possible_if_statements = possible_if_statements.reject { |element| element.include?("else") }

      possible_if_statements = possible_if_statements.reject { |element| element.lstrip.include?(" if ") }

      if !possible_if_statements.empty?

        if_statement_indexes = []

        possible_if_statements.each do |statement|

          if_statement_indexes << input_file_contents.dup.each_index.select { |index| input_file_contents[index] == statement }

        end

        if_statement_indexes = [0] + if_statement_indexes.flatten + [-1]

        controlregexp = /(while |def )/

        modified_input_contents, extracted_statements = extract_if_blocks(if_statement_indexes, input_file_contents.clone)

        joined_blocks = extracted_statements.collect { |element| element.join }

        if_statements = joined_blocks.reject { |element| element.index(controlregexp) != nil }

        rejected_elements = joined_blocks - if_statements

        rejected_elements_index = []

        rejected_elements.each do |element|

          rejected_elements_index << joined_blocks.each_index.select { |index| joined_blocks[index] == element }

        end

        if_blocks_index = (0...extracted_statements.length).to_a

        rejected_elements_index = rejected_elements_index.flatten

        if_blocks_index -= rejected_elements_index

        modified_if_statements = if_statements.collect { |string| convert_string_to_array(string, temporary_nila_file) }

        modified_if_statements = modified_if_statements.collect { |block| compile_if_syntax(block) }.reverse

        if_blocks_index = if_blocks_index.collect { |element| "--ifblock#{element}" }.reverse

        rejected_elements_index = rejected_elements_index.collect { |element| "--ifblock#{element}" }.reverse

        rejected_elements = rejected_elements.reverse

        joined_file_contents = modified_input_contents.join

        until if_blocks_index.empty? and rejected_elements_index.empty?

          if !if_blocks_index.empty?

            if joined_file_contents.include?(if_blocks_index[0])

              joined_file_contents = joined_file_contents.sub(if_blocks_index[0], modified_if_statements[0].join)

              if_blocks_index.delete_at(0)

              modified_if_statements.delete_at(0)

            else

              joined_file_contents = joined_file_contents.sub(rejected_elements_index[0], rejected_elements[0])

              rejected_elements_index.delete_at(0)

              rejected_elements.delete_at(0)

            end

          else

            joined_file_contents = joined_file_contents.sub(rejected_elements_index[0], rejected_elements[0])

            rejected_elements_index.delete_at(0)

            rejected_elements.delete_at(0)

          end

        end

      else

        joined_file_contents = input_file_contents.join

      end

      file_id = open(temporary_nila_file, 'w')

      file_id.write(joined_file_contents)

      file_id.close()

      line_by_line_contents = read_file_line_by_line(temporary_nila_file)

      return line_by_line_contents

    end

    def compile_regular_while(input_file_contents, temporary_nila_file)

      def convert_string_to_array(input_string, temporary_nila_file)

        file_id = open(temporary_nila_file, 'w')

        file_id.write(input_string)

        file_id.close()

        line_by_line_contents = read_file_line_by_line(temporary_nila_file)

        return line_by_line_contents

      end

      def extract_while_blocks(while_statement_indexes, input_file_contents)

        possible_while_blocks = []

        while_block_counter = 0

        extracted_blocks = []

        controlregexp = /(if |while |def )/

        rejectionregexp = /( if | while )/

        for x in 0...while_statement_indexes.length-1

          possible_while_blocks << input_file_contents[while_statement_indexes[x]..while_statement_indexes[x+1]]

        end

        end_counter = 0

        end_index = []

        current_block = []

        possible_while_blocks.each_with_index do |block|

          current_block += block

          current_block.each_with_index do |line, index|

            if line.strip.eql? "end"

              end_counter += 1

              end_index << index

            end

          end

          if end_counter > 0

            until end_index.empty?

              array_extract = current_block[0..end_index[0]].reverse

              index_counter = 0

              array_extract.each_with_index do |line|

                break if (line.lstrip.index(controlregexp) != nil and line.lstrip.index(rejectionregexp).nil?)

                index_counter += 1

              end

              block_extract = array_extract[0..index_counter].reverse

              extracted_blocks << block_extract

              block_start = current_block.index(block_extract[0])

              block_end = current_block.index(block_extract[-1])

              current_block[block_start..block_end] = "--whileblock#{while_block_counter}"

              while_block_counter += 1

              end_counter = 0

              end_index = []

              current_block.each_with_index do |line, index|

                if line.strip.eql? "end"

                  end_counter += 1

                  end_index << index

                end

              end

            end

          end

        end

        return current_block, extracted_blocks

      end

      def compile_while_syntax(input_block)

        modified_input_block = input_block.dup

        strings = []

        string_counter = 0

        input_block.each_with_index do |line, index|

          if line.include?("\"")

            opening_quotes = line.index("\"")

            string_extract = line[opening_quotes..line.index("\"", opening_quotes+1)]

            strings << string_extract

            modified_input_block[index] = modified_input_block[index].sub(string_extract, "--string{#{string_counter}}")

            string_counter += 1

          end

        end

        input_block = modified_input_block

        starting_line = input_block[0]

        starting_line = starting_line + "\n" if starting_line.lstrip == starting_line

        junk, condition = starting_line.split("while")

        input_block[0] = "whaaleskey (#{condition.lstrip.rstrip.gsub("?", "")}) {\n"

        input_block[-1] = input_block[-1].lstrip.sub("end", "}")

        modified_input_block = input_block.dup

        input_block.each_with_index do |line, index|

          if line.include?("--string{")

            junk, remains = line.split("--string{")

            string_index, junk = remains.split("}")

            modified_input_block[index] = modified_input_block[index].sub("--string{#{string_index.strip}}", strings[string_index.strip.to_i])

          end

        end

        return modified_input_block

      end

      possible_while_statements = input_file_contents.reject { |element| !element.include?("while") }

      if !possible_while_statements.empty?

        while_statement_indexes = []

        possible_while_statements.each do |statement|

          while_statement_indexes << input_file_contents.dup.each_index.select { |index| input_file_contents[index] == statement }

        end

        while_statement_indexes = [0] + while_statement_indexes.flatten + [-1]

        controlregexp = /(if |def )/

        modified_input_contents, extracted_statements = extract_while_blocks(while_statement_indexes, input_file_contents.clone)

        joined_blocks = extracted_statements.collect { |element| element.join }

        while_statements = joined_blocks.reject { |element| element.index(controlregexp) != nil }

        rejected_elements = joined_blocks - while_statements

        rejected_elements_index = []

        rejected_elements.each do |element|

          rejected_elements_index << joined_blocks.each_index.select { |index| joined_blocks[index] == element }

        end

        while_blocks_index = (0...extracted_statements.length).to_a

        rejected_elements_index = rejected_elements_index.flatten

        while_blocks_index -= rejected_elements_index

        modified_while_statements = while_statements.collect { |string| convert_string_to_array(string, temporary_nila_file) }

        modified_while_statements = modified_while_statements.collect { |block| compile_while_syntax(block) }.reverse

        while_blocks_index = while_blocks_index.collect { |element| "--whileblock#{element}" }.reverse

        rejected_elements_index = rejected_elements_index.collect { |element| "--whileblock#{element}" }.reverse

        rejected_elements = rejected_elements.reverse

        joined_file_contents = modified_input_contents.join

        until while_blocks_index.empty? and rejected_elements_index.empty?

          if !while_blocks_index.empty?

            if joined_file_contents.include?(while_blocks_index[0])

              joined_file_contents = joined_file_contents.sub(while_blocks_index[0], modified_while_statements[0].join)

              while_blocks_index.delete_at(0)

              modified_while_statements.delete_at(0)

            else

              joined_file_contents = joined_file_contents.sub(rejected_elements_index[0], rejected_elements[0].join)

              rejected_elements_index.delete_at(0)

              rejected_elements.delete_at(0)

            end

          else

            joined_file_contents = joined_file_contents.sub(rejected_elements_index[0], rejected_elements[0].join)

            rejected_elements_index.delete_at(0)

            rejected_elements.delete_at(0)

          end

        end

      else

        joined_file_contents = input_file_contents.join

      end

      file_id = open(temporary_nila_file, 'w')

      file_id.write(joined_file_contents)

      file_id.close()

      line_by_line_contents = read_file_line_by_line(temporary_nila_file)

      return line_by_line_contents

    end

    def compile_loop_keyword(input_file_contents,temporary_nila_file)

      def convert_string_to_array(input_string, temporary_nila_file)

        file_id = open(temporary_nila_file, 'w')

        file_id.write(input_string)

        file_id.close()

        line_by_line_contents = read_file_line_by_line(temporary_nila_file)

        return line_by_line_contents

      end

      def extract_loop_blocks(loop_statement_indexes, input_file_contents)

        possible_loop_blocks = []

        loop_block_counter = 0

        extracted_blocks = []

        controlregexp = /(if |while |def |loop )/

        rejectionregexp = /( if | while )/

        for x in 0...loop_statement_indexes.length-1

          possible_loop_blocks << input_file_contents[loop_statement_indexes[x]..loop_statement_indexes[x+1]]

        end

        end_counter = 0

        end_index = []

        current_block = []

        possible_loop_blocks.each_with_index do |block|

          current_block += block

          current_block.each_with_index do |line, index|

            if line.strip.eql? "end"

              end_counter += 1

              end_index << index

            end

          end

          if end_counter > 0

            until end_index.empty?

              array_extract = current_block[0..end_index[0]].reverse

              index_counter = 0

              array_extract.each_with_index do |line|

                break if (line.lstrip.index(controlregexp) != nil and line.lstrip.index(rejectionregexp).nil?)

                index_counter += 1

              end

              block_extract = array_extract[0..index_counter].reverse

              extracted_blocks << block_extract

              block_start = current_block.index(block_extract[0])

              block_end = current_block.index(block_extract[-1])

              current_block[block_start..block_end] = "--loopblock#{loop_block_counter}"

              loop_block_counter += 1

              end_counter = 0

              end_index = []

              current_block.each_with_index do |line, index|

                if line.strip.eql? "end"

                  end_counter += 1

                  end_index << index

                end

              end

            end

          end

        end

        return current_block, extracted_blocks

      end

      def compile_loop_syntax(input_block)

        modified_input_block = input_block.dup

        strings = []

        string_counter = 0

        input_block.each_with_index do |line, index|

          if line.include?("\"")

            opening_quotes = line.index("\"")

            string_extract = line[opening_quotes..line.index("\"", opening_quotes+1)]

            strings << string_extract

            modified_input_block[index] = modified_input_block[index].sub(string_extract, "--string{#{string_counter}}")

            string_counter += 1

          end

        end

        input_block = modified_input_block

        starting_line = input_block[0]

        starting_line = starting_line + "\n" if starting_line.lstrip == starting_line

        input_block[0] = "whaaleskey (true) {\n"

        input_block[-1] = input_block[-1].lstrip.sub("end", "}")

        modified_input_block = input_block.dup

        input_block.each_with_index do |line, index|

          if line.include?("--string{")

            junk, remains = line.split("--string{")

            string_index, junk = remains.split("}")

            modified_input_block[index] = modified_input_block[index].sub("--string{#{string_index.strip}}", strings[string_index.strip.to_i])

          end

        end

        return modified_input_block

      end

      possible_loop_statements = input_file_contents.reject { |element| !element.include?("loop") }

      if !possible_loop_statements.empty?

        loop_statement_indexes = []

        possible_loop_statements.each do |statement|

          loop_statement_indexes << input_file_contents.dup.each_index.select { |index| input_file_contents[index] == statement }

        end

        loop_statement_indexes = [0] + loop_statement_indexes.flatten + [-1]

        controlregexp = /(if |def )/

        modified_input_contents, extracted_statements = extract_loop_blocks(loop_statement_indexes, input_file_contents.clone)

        joined_blocks = extracted_statements.collect { |element| element.join }

        loop_statements = joined_blocks.reject { |element| element.index(controlregexp) != nil }

        rejected_elements = joined_blocks - loop_statements

        rejected_elements_index = []

        rejected_elements.each do |element|

          rejected_elements_index << joined_blocks.each_index.select { |index| joined_blocks[index] == element }

        end

        loop_blocks_index = (0...extracted_statements.length).to_a

        rejected_elements_index = rejected_elements_index.flatten

        loop_blocks_index -= rejected_elements_index

        modified_loop_statements = loop_statements.collect { |string| convert_string_to_array(string, temporary_nila_file) }

        modified_loop_statements = modified_loop_statements.collect { |block| compile_loop_syntax(block) }.reverse

        loop_blocks_index = loop_blocks_index.collect { |element| "--loopblock#{element}" }.reverse

        rejected_elements_index = rejected_elements_index.collect { |element| "--loopblock#{element}" }.reverse

        rejected_elements = rejected_elements.reverse

        joined_file_contents = modified_input_contents.join

        until loop_blocks_index.empty? and rejected_elements_index.empty?

          if !loop_blocks_index.empty?

            if joined_file_contents.include?(loop_blocks_index[0])

              joined_file_contents = joined_file_contents.sub(loop_blocks_index[0], modified_loop_statements[0].join)

              loop_blocks_index.delete_at(0)

              modified_loop_statements.delete_at(0)

            else

              joined_file_contents = joined_file_contents.sub(rejected_elements_index[0], rejected_elements[0].join)

              rejected_elements_index.delete_at(0)

              rejected_elements.delete_at(0)

            end

          else

            joined_file_contents = joined_file_contents.sub(rejected_elements_index[0], rejected_elements[0].join)

            rejected_elements_index.delete_at(0)

            rejected_elements.delete_at(0)

          end

        end

      else

        joined_file_contents = input_file_contents.join

      end

      file_id = open(temporary_nila_file, 'w')

      file_id.write(joined_file_contents)

      file_id.close()

      line_by_line_contents = read_file_line_by_line(temporary_nila_file)

      return line_by_line_contents

    end

    def ignore_statement_modifiers(input_block)

      modified_input_block = input_block.dup

      rejectionregexp = /( if | while )/

      rejected_lines = {}

      rejected_line_counter = 0

      input_block.each_with_index do |line, index|

        if line.lstrip.index(rejectionregexp) != nil

          rejected_lines["--rejected{#{rejected_line_counter}}\n\n"] = line

          modified_input_block[index] = "--rejected{#{rejected_line_counter}}\n\n"

          rejected_line_counter += 1

        end

      end

      return modified_input_block, rejected_lines

    end

    def replace_statement_modifiers(input_block, rejected_lines)

      unless rejected_lines.empty?

        rejected_replacements = rejected_lines.keys

        loc = 0

        indices = []

        index_counter = 0

        rejected_replacements.each do |replacement_string|

          input_block.each_with_index do |line, index|

            break if line.include?(replacement_string.rstrip)

            index_counter += 1

          end

          indices << index_counter

          index_counter = 0

        end

        indices.each_with_index do |location, index|

          input_block[location] = rejected_lines.values[index] + "\n\n"

        end

      end

      return input_block

    end

    file_contents, rejected_lines = ignore_statement_modifiers(input_file_contents)

    file_contents = replace_unless_until(file_contents)

    file_contents = compile_regular_if(file_contents, temporary_nila_file)

    file_contents = compile_regular_while(file_contents, temporary_nila_file)

    file_contents = compile_loop_keyword(file_contents,temporary_nila_file)

    file_contents = replace_statement_modifiers(file_contents, rejected_lines)

    file_contents = compile_inline_conditionals(file_contents, temporary_nila_file)

    return file_contents

  end

  def add_semicolons(input_file_contents)

    def comment(input_string)

      if input_string.include?("--single_line_comment")

        true

      elsif input_string.include?("--multiline_comment")

        true

      else

        false

      end

    end

    reject_regexp = /(function |Euuf |if |else|elsuf|switch |case|while |whaaleskey |for )/

    modified_file_contents = input_file_contents.dup

    input_file_contents.each_with_index do |line,index|

      if line.index(reject_regexp) == nil

        if !comment(line)

          if !line.lstrip.eql?("")

            if !line.lstrip.eql?("}\n")

              if !line.lstrip.eql?("}\n\n")

                if line.rstrip[-1] != "[" and line.rstrip[-1] != "{" and line.rstrip[-1] != "," and line.rstrip[-1] != ";"

                  modified_file_contents[index] = line.rstrip + ";\n\n"

                end

              end

            end

          end

        end

      end

    end

    modified_file_contents

  end

  def compile_comments(input_file_contents, comments, temporary_nila_file)

    #This method converts Nila comments into pure Javascript comments. This method
    #handles both single line and multiline comments.

    file_contents_as_string = input_file_contents.join

    single_line_comments = comments[0]

    multiline_comments = comments[1]

    single_line_comment_counter = 1

    multi_line_comment_counter = 1

    ignorable_keywords = [/if/, /while/, /function/]

    dummy_replacement_words = ["eeuuff", "whaalesskkey", "conffoolotion"]

    for x in 0...single_line_comments.length

      current_singleline_comment = "--single_line_comment[#{single_line_comment_counter}]"

      replacement_singleline_string = single_line_comments[x].sub("#", "//")

      ignorable_keywords.each_with_index do |keyword, index|

        if replacement_singleline_string.index(keyword) != nil

          replacement_singleline_string = replacement_singleline_string.sub(keyword.inspect[1...-1], dummy_replacement_words[index])

        end

      end

      file_contents_as_string = file_contents_as_string.sub(current_singleline_comment, replacement_singleline_string)

      single_line_comment_counter += 1


    end

    for y in 0...multiline_comments.length

      current_multiline_comment = "--multiline_comment[#{multi_line_comment_counter}]"

      replacement_multiline_string = multiline_comments[y].sub("=begin", "/*\n")

      replacement_multiline_string = replacement_multiline_string.sub("=end", "\n*/")

      ignorable_keywords.each_with_index do |keyword, index|

        if replacement_multiline_string.index(keyword) != nil

          replacement_multiline_string = replacement_multiline_string.sub(keyword.inspect[1...-1], dummy_replacement_words[index])

        end

      end

      file_contents_as_string = file_contents_as_string.sub(current_multiline_comment, replacement_multiline_string)

      multi_line_comment_counter += 1

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(file_contents_as_string)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    line_by_line_contents

  end

  def pretty_print_javascript(javascript_file_contents, temporary_nila_file)

    def reset_tabs(input_file_contents)

      #This method removes all the predefined tabs to avoid problems in
      #later parts of the beautifying process.

      for x in 0...input_file_contents.length

        current_row = input_file_contents[x]

        if !current_row.eql?("\n")

          current_row = current_row.lstrip

        end

        input_file_contents[x] = current_row


      end

      return input_file_contents

    end

    def find_all_matching_indices(input_string, pattern)

      locations = []

      index = input_string.index(pattern)

      while index != nil

        locations << index

        index = input_string.index(pattern, index+1)


      end

      return locations


    end

    def convert_string_to_array(input_string, temporary_nila_file)

      file_id = open(temporary_nila_file, 'w')

      file_id.write(input_string)

      file_id.close()

      line_by_line_contents = read_file_line_by_line(temporary_nila_file)

      return line_by_line_contents

    end

    def fix_newlines(file_contents)

      def extract_blocks(file_contents)

        javascript_regexp = /(if |while |function |function\(|((=|:)\s+\{))/

        block_starting_lines = file_contents.dup.reject { |element| element.index(javascript_regexp).nil? }[1..-1]

        block_starting_lines = block_starting_lines.reject { |element| element.include?("    ") }

        initial_starting_lines = block_starting_lines.dup

        starting_line_indices = []

        block_starting_lines.each do |line|

          starting_line_indices << file_contents.index(line)

        end

        block_ending_lines = file_contents.dup.each_index.select { |index| (file_contents[index].eql? "  }\n" or file_contents[index].eql? "  };\n")}

        modified_file_contents = file_contents.dup

        code_blocks = []

        starting_index = starting_line_indices[0]

        begin

          for x in 0...initial_starting_lines.length

            code_blocks << modified_file_contents[starting_index..block_ending_lines[0]]

            modified_file_contents[starting_index..block_ending_lines[0]] = []

            modified_file_contents.insert(starting_index, "  *****")

            block_starting_lines = modified_file_contents.dup.reject { |element| element.index(javascript_regexp).nil? }[1..-1]

            block_starting_lines = block_starting_lines.reject { |element| element.include?("    ") }

            starting_line_indices = []

            block_starting_lines.each do |line|

              starting_line_indices << modified_file_contents.index(line)

            end

            block_ending_lines = modified_file_contents.dup.each_index.select { |index| (modified_file_contents[index].eql? "  }\n" or modified_file_contents[index].eql? "  };\n") }

            starting_index = starting_line_indices[0]

          end

        rescue TypeError

          puts "Whitespace was left unfixed!"

        rescue ArgumentError

          puts "Whitespace was left unfixed!"

        end

        return modified_file_contents, code_blocks

      end

      compact_contents = file_contents.reject { |element| element.lstrip.eql? "" }

      compact_contents, code_blocks = extract_blocks(compact_contents)

      processed_contents = compact_contents[1...-1].collect { |line| line+"\n" }

      compact_contents = [compact_contents[0]] + processed_contents + [compact_contents[-1]]

      code_block_locations = compact_contents.each_index.select { |index| compact_contents[index].eql? "  *****\n" }

      initial_locations = code_block_locations.dup

      starting_index = code_block_locations[0]

      for x in 0...initial_locations.length

        code_blocks[x][-1] = code_blocks[x][-1] + "\n"

        compact_contents = compact_contents[0...starting_index] + code_blocks[x] + compact_contents[starting_index+1..-1]

        code_block_locations = compact_contents.each_index.select { |index| compact_contents[index].eql? "  *****\n" }

        starting_index = code_block_locations[0]


      end

      return compact_contents

    end

    def roll_blocks(input_file_contents, code_block_starting_locations)

      if !code_block_starting_locations.empty?

        controlregexp = /(if |while |function |function\(|((=|:)\s+\{))/

        code_block_starting_locations = [0, code_block_starting_locations, -1].flatten

        possible_blocks = []

        block_counter = 0

        extracted_blocks = []

        for x in 0...code_block_starting_locations.length-1

          possible_blocks << input_file_contents[code_block_starting_locations[x]..code_block_starting_locations[x+1]]

        end

        end_counter = 0

        end_index = []

        current_block = []

        possible_blocks.each_with_index do |block|

          current_block += block

          current_block.each_with_index do |line, index|

            if line.lstrip.eql? "}\n" or line.lstrip.eql?("};\n")

              end_counter += 1

              end_index << index

            end

          end

          if end_counter > 0

            until end_index.empty?

              array_extract = current_block[0..end_index[0]].reverse

              index_counter = 0

              array_extract.each_with_index do |line|

                break if line.index(controlregexp) != nil

                index_counter += 1

              end

              block_extract = array_extract[0..index_counter].reverse

              extracted_blocks << block_extract

              block_start = current_block.index(block_extract[0])

              block_end = current_block.index(block_extract[-1])

              current_block[block_start..block_end] = "--block#{block_counter}"

              block_counter += 1

              end_counter = 0

              end_index = []

              current_block.each_with_index do |line, index|

                if line.lstrip.eql? "}\n"

                  end_counter += 1

                  end_index << index

                end

              end

            end

          end

        end

        return current_block, extracted_blocks

      else

        return input_file_contents, []

      end

    end

    def fix_syntax_indentation(input_file_contents)

      fixableregexp = /(else |elsuf )/

      need_fixes = input_file_contents.reject { |line| line.index(fixableregexp).nil? }

      need_fixes.each do |fix|

        input_file_contents[input_file_contents.index(fix)] = input_file_contents[input_file_contents.index(fix)].sub("  ", "")

      end

      return input_file_contents

    end

    def replace_ignored_words(input_string)

      ignorable_keywords = [/if/, /while/, /function/]

      dummy_replacement_words = ["eeuuff", "whaalesskkey", "conffoolotion"]

      dummy_replacement_words.each_with_index do |word, index|

        input_string = input_string.sub(word, ignorable_keywords[index].inspect[1...-1])

      end

      return input_string

    end

    javascript_regexp = /(if |while |function |function\(|((=|:)\s+\{))/

    javascript_file_contents = javascript_file_contents.collect { |element| element.sub("Euuf", "if") }

    javascript_file_contents = javascript_file_contents.collect { |element| element.sub("whaaleskey", "while") }

    javascript_file_contents = reset_tabs(javascript_file_contents)

    starting_locations = []

    javascript_file_contents.each_with_index do |line, index|

      if line.index(javascript_regexp) != nil

        starting_locations << index

      end

    end

    remaining_file_contents, blocks = roll_blocks(javascript_file_contents, starting_locations)

    joined_file_contents = ""

    if !blocks.empty?

      remaining_file_contents = remaining_file_contents.collect { |element| "  " + element }

      main_blocks = remaining_file_contents.reject { |element| !element.include?("--block") }

      main_block_numbers = main_blocks.collect { |element| element.split("--block")[1] }

      modified_blocks = main_blocks.dup

      soft_tabs = "  "

      for x in (0...main_blocks.length)

        soft_tabs_counter = 1

        current_block = blocks[main_block_numbers[x].to_i]

        current_block = [soft_tabs + current_block[0]] + current_block[1...-1] + [soft_tabs*(soft_tabs_counter)+current_block[-1]]

        soft_tabs_counter += 1

        current_block = [current_block[0]] + current_block[1...-1].collect { |element| soft_tabs*(soft_tabs_counter)+element } + [current_block[-1]]

        nested_block = current_block.reject { |row| !row.include?("--block") }

        nested_block = nested_block.collect { |element| element.split("--block")[1] }

        nested_block = nested_block.collect { |element| element.rstrip.to_i }

        modified_nested_block = nested_block.clone

        current_block = current_block.join

        until modified_nested_block.empty?

          nested_block.each do |block_index|

            nested_block_contents = blocks[block_index]

            nested_block_contents = nested_block_contents[0...-1] + [soft_tabs*(soft_tabs_counter)+nested_block_contents[-1]]

            soft_tabs_counter += 1

            nested_block_contents = [nested_block_contents[0]] + nested_block_contents[1...-1].collect { |element| soft_tabs*(soft_tabs_counter)+element } + [nested_block_contents[-1]]

            nested_block_contents = nested_block_contents.reject { |element| element.gsub(" ", "").eql?("") }

            current_block = current_block.sub("--block#{block_index}", nested_block_contents.join)

            blocks[block_index] = nested_block_contents

            modified_nested_block.delete_at(0)

            soft_tabs_counter -= 1

          end

          current_block = convert_string_to_array(current_block, temporary_nila_file)

          nested_block = current_block.reject { |element| !element.include?("--block") }

          nested_block = nested_block.collect { |element| element.split("--block")[1] }

          nested_block = nested_block.collect { |element| element.rstrip.to_i }

          modified_nested_block = nested_block.clone

          current_block = current_block.join

          if !nested_block.empty?

            soft_tabs_counter += 1

          end

        end

        modified_blocks[x] = current_block

      end

      remaining_file_contents = ["(function() {\n", remaining_file_contents, "\n}).call(this);"].flatten

      joined_file_contents = remaining_file_contents.join

      main_blocks.each_with_index do |block_id, index|

        joined_file_contents = joined_file_contents.sub(block_id, modified_blocks[index])

      end

    else

      remaining_file_contents = remaining_file_contents.collect { |element| "  " + element }

      remaining_file_contents = ["(function() {\n", remaining_file_contents, "\n}).call(this);"].flatten

      joined_file_contents = remaining_file_contents.join

    end

    file_id = open(temporary_nila_file, 'w')

    file_id.write(joined_file_contents)

    file_id.close()

    line_by_line_contents = read_file_line_by_line(temporary_nila_file)

    line_by_line_contents = fix_newlines(line_by_line_contents)

    line_by_line_contents = fix_syntax_indentation(line_by_line_contents)

    line_by_line_contents = line_by_line_contents.collect { |element| replace_ignored_words(element) }

    return line_by_line_contents

  end

  def compile_operators(input_file_contents)

    def compile_power_operator(input_string)

      matches = input_string.scan(/(\w{1,}\*\*\w{1,})/).to_a.flatten

      unless matches.empty?

        matches.each do |match|

          left, right = match.split("**")

          input_string = input_string.sub(match, "Math.pow(#{left},#{right})")

        end

      end

      return input_string

    end

    def compile_match_operator(input_string)

      rejection_exp = /( aannddy | orriioo |nnoottyy )/

      if input_string.include?("=~")

        input_string = input_string.gsub(" && "," aannddy ").gsub(" || "," orriioo ").gsub("!","nnoottyy")

        left, right = input_string.split("=~")

        if left.index(rejection_exp) != nil

          left = left[left.index(rejection_exp)..-1]

        elsif left.index(/\(/)

          left = left[left.index(/\(/)+1..-1]

        end

        if right.index(rejection_exp) != nil

          right = right[0...right.index(rejection_exp)]

        elsif right.index(/\)/)

          right = right[0...right.index(/\)/)]

        end

        original_string = "#{left}=~#{right}"

        replacement_string = "#{left.rstrip} = #{left.rstrip}.match(#{right.lstrip.rstrip})"

        input_string = input_string.sub(original_string,replacement_string)

        input_string = input_string.gsub(" aannddy "," && ").gsub(" orriioo "," || ").gsub("nnoottyy","!")

      end

      return input_string

    end

    input_file_contents = input_file_contents.collect { |element| element.sub("==", "===") }

    input_file_contents = input_file_contents.collect { |element| element.sub("!=", "!==") }

    input_file_contents = input_file_contents.collect { |element| element.sub("elsuf", "else if") }

    input_file_contents = input_file_contents.collect { |element| compile_power_operator(element) }

    input_file_contents = input_file_contents.collect {|element| compile_match_operator(element)}

    return input_file_contents

  end

  def pretty_print_nila(input_file_contents, temporary_nila_file)


  end

  def output_javascript(file_contents, output_file, temporary_nila_file)

    file_id = open(output_file, 'w')

    File.delete(temporary_nila_file)

    file_id.write("//Written using Nila. Visit http://adhithyan15.github.io/nila\n")

    file_id.write(file_contents.join)

    file_id.close()

  end

  if File.exist?(input_file_path)

    file_contents = read_file_line_by_line(input_file_path)

    file_contents = extract_parsable_file(file_contents)

    file_contents, multiline_comments, temp_file, output_js_file = replace_multiline_comments(file_contents, input_file_path, *output_file_name)

    file_contents, singleline_comments = replace_singleline_comments(file_contents)

    file_contents = split_semicolon_seperated_expressions(file_contents)

    file_contents = compile_heredocs(file_contents, temp_file)

    file_contents = compile_interpolated_strings(file_contents)

    file_contents = compile_hashes(file_contents,temp_file)

    file_contents = compile_conditional_structures(file_contents, temp_file)

    file_contents = compile_arrays(file_contents, temp_file)

    file_contents = compile_strings(file_contents)

    file_contents = compile_default_values(file_contents, temp_file)

    file_contents, named_functions, nested_functions = replace_named_functions(file_contents, temp_file)

    comments = [singleline_comments, multiline_comments]

    file_contents = compile_parallel_assignment(file_contents, temp_file)

    list_of_variables, file_contents = get_variables(file_contents, temp_file)

    file_contents, function_names = compile_named_functions(file_contents, named_functions, nested_functions, temp_file)

    file_contents, ruby_functions = compile_custom_function_map(file_contents)

    function_names << ruby_functions

    file_contents = compile_whitespace_delimited_functions(file_contents, function_names, temp_file)

    file_contents = remove_question_marks(file_contents, list_of_variables, temp_file)

    file_contents = add_semicolons(file_contents)

    file_contents = compile_comments(file_contents, comments, temp_file)

    file_contents = pretty_print_javascript(file_contents, temp_file)

    file_contents = compile_operators(file_contents)

    output_javascript(file_contents, output_js_file, temp_file)

    puts "Compilation is successful!"

  else

    puts "File doesn't exist!"

  end

end

def create_mac_executable(input_file)

  def read_file_line_by_line(input_path)

    file_id = open(input_path)

    file_line_by_line = file_id.readlines()

    file_id.close

    return file_line_by_line

  end

  mac_file_contents = ["#!/usr/bin/env ruby\n\n"] + read_file_line_by_line(input_file)

  mac_file_path = input_file.sub(".rb", "")

  file_id = open(mac_file_path, "w")

  file_id.write(mac_file_contents.join)

  file_id.close

end

def find_file_name(input_path, file_extension)

  extension_remover = input_path.split(file_extension)

  remaining_string = extension_remover[0].reverse

  path_finder = remaining_string.index("/")

  remaining_string = remaining_string.reverse

  return remaining_string[remaining_string.length-path_finder..-1]

end

def find_file_path(input_path, file_extension)

  extension_remover = input_path.split(file_extension)

  remaining_string = extension_remover[0].reverse

  path_finder = remaining_string.index("/")

  remaining_string = remaining_string.reverse

  return remaining_string[0...remaining_string.length-path_finder]

end

nilac_version = "0.0.4.2.1"

opts = Slop.parse do
  on :c, :compile=, 'Compile Nila File', as:Array, delimiter:":"
  on :h, :help, 'Help With Nilac' do

    puts "Nilac is the official compiler for the Nila language.This is a basic help\nmessage with pointers to more information.\n\n"

    puts "  Basic Usage:\n\n"

    puts "    nilac -h/--help\n"

    puts "    nilac -v/--version\n"

    puts "    nilac -u/--update => Update Checker\n"

    puts "    nilac [command] [file_options]\n\n"

    puts "  Available Commands:\n\n"

    puts "    nilac -c [nila_file] => Compile Nila File\n\n"

    puts "    nilac -c [nila_file]:[output_js_file] => Compile nila_file and saves it as\n    output_js_file\n\n"

    puts "    nilac -c [nila_file_folder] => Compiles each .nila file in the nila_folder\n\n"

    puts "    nilac -c [nila_file_folder]:[output_js_file_folder] => Compiles each .nila\n    file in the nila_folder and saves it in the output_js_file_folder\n\n"

    puts "    nilac -r [nila_file] => Compile and Run nila_file\n\n"

    puts "  Further Information:\n\n"

    puts "    Visit http://adhithyan15.github.io/nila to know more about the project.\n\n"

  end
  on :v, :version, 'Output Nilac Version No' do

    puts nilac_version

  end

  on :r, :run=, 'Run Nila File', as:Array

  on :b, :build, 'Build Nilac for Linux/Mac/Rubygems' do

    file_path = Dir.pwd + "/src/nilac.rb"

    create_mac_executable(file_path)

    FileUtils.mv("#{file_path[0...-3]}", "#{Dir.pwd}/bin/nilac")

    puts "Build Successful!"

  end

  on :u, :update, 'Check if Nilac is up to date.' do

    outdated_gems = `gem outdated`

    outdated_gems = outdated_gems.split("\n")

    outdated = false

    old_version = ""

    new_version = ""

    outdated_gems.each do |gem_name|

      if gem_name.include?("nilac")

        outdated = true

        old_version = gem_name.split("(")[1].split(")")[0].split("<")[0].lstrip

        new_version = gem_name.split("(")[1].split(")")[0].split("<")[1].lstrip.rstrip

        break

      end

    end

    if outdated

      exec = `gem update nilac`

      puts "Your version of Nilac (#{old_version}) was outdated! We have automatically updated you to the latest version (#{new_version})."


    else

      puts "Your version of Nilac is up to date!"

    end

  end
end

opts = opts.to_hash

if opts[:compile] != nil

  if opts[:compile].length == 1

    input = opts[:compile][0]

    if input.include? ".nila"

      current_directory = Dir.pwd

      input_file = input

      file_path = current_directory + "/" + input_file

      compile(file_path)

    elsif input.include? "/"

      folder_path = input

      files = Dir.glob(File.join(folder_path, "*"))

      files = files.reject { |path| !path.include? ".nila" }

      files.each do |file|

        file_path = Dir.pwd + "/" + file

        compile(file_path)

      end

    end

  elsif opts[:compile].length == 2

    input = opts[:compile][0]

    output = opts[:compile][1]

    if input.include? ".nila" and output.include? ".js"

      input_file = input

      output_file = output

      input_file_path = input_file

      output_file_path = output_file

      compile(input_file_path, output_file_path)

    elsif input[-1].eql? "/" and output[-1].eql? "/"

      input_folder_path = input

      output_folder_path = output

      if !File.directory?(output_folder_path)

        FileUtils.mkdir_p(output_folder_path)

      end

      files = Dir.glob(File.join(input_folder_path, "*"))

      files = files.reject { |path| !path.include? ".nila" }

      files.each do |file|

        input_file_path = file

        output_file_path = output_folder_path + find_file_name(file, ".nila") + ".js"

        compile(input_file_path, output_file_path)

      end

    end

  end

elsif opts[:run] != nil

  current_directory = Dir.pwd

  file = opts[:run][0]

  file_path = current_directory + "/" + file

  compile(file_path)

  js_file_name = find_file_path(file_path, ".nila") + find_file_name(file_path, ".nila") + ".js"

  node_output = `node #{js_file_name}`

  puts node_output

end