#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}]") 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_interpolated_strings(input_file_contents) modified_file_contents = input_file_contents.dup input_file_contents.each_with_index do |line,index| if line.include?("\#{") interpolated_strings = line.scan(/\#{\S{1,}}/) 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}]") 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.include?("end\n") || current_row.include?("end") end_locations << x end end 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 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 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 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 get_variables(input_file_contents,temporary_nila_file) #This method is solely focused on getting a list of variables to be declared. #Since Javascript is a dynamic language, Nila doesn't have to worry about following up on those variables. #Semicolons are required in Javascript for successful compilation. So this method adds semicolons at the end of each #variable usage statements. variables = [] for x in 0...input_file_contents.length current_row = input_file_contents[x] #The condition below verifies if the rows contain any equation operators. 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 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.join(", ") + "\n\n" line_by_line_contents = [variable_declaration_string,line_by_line_contents].flatten end 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) #Currently the following kinds of array constructs are compilable # 1. %w{} syntax # 2. Range - Coming soon! 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_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 variables = [] input_function_block.each do |line| if line.include? "=" and !line.include?("def") current_line_split = line.strip.split("=") variables << current_line_split[0].rstrip end end variables.uniq 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.reject {|content| content.strip.eql? "}"} last_statement = rejected_array[0] replacement_string = "return #{last_statement.lstrip}" input_array[input_array.index(last_statement)] = replacement_string 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" 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) 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 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 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", "print" => "console.log" } 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 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.sub(function+" ",function+"(") modified_string = modified_string.sub("\n",")\n") joined_file_contents = joined_file_contents.sub(string,modified_string) end 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_conditional_structures(input_file_contents,temporary_nila_file) #Currently the following conditional structures have been implemented #1. If and While Inline Statements def compile_inline_conditionals(input_file_contents,temporary_nila_file) conditionals = [/( if )/,/( while )/] plain_conditionals = [" if "," while "] 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)} matching_lines.each do |line| line_split = line.split(plain_conditionals[index]) if index == 0 output_statement = "if (#{line_split[1].lstrip.rstrip}) {\n\n#{line_split[0]}\n}\n" elsif index == 1 output_statement = "while (#{line_split[1].lstrip.rstrip}) {\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 line_by_line_contents = compile_inline_conditionals(input_file_contents,temporary_nila_file) 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 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("#","//") 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*/") 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 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 |if |else|switch |case|while |for )/ modified_file_contents = [] input_file_contents.each do |line| if line.index(reject_regexp) == nil if !comment(line) if !line.lstrip.eql?("") if !line.lstrip.eql?("}\n") if !line.lstrip.eql?("}\n\n") modified_file_contents << line.rstrip + ";\n\n" else modified_file_contents << line end else modified_file_contents << line end else modified_file_contents << line end else modified_file_contents << line end else modified_file_contents << line end end modified_file_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 previous_formatting(input_string,tab_counter,temporary_nila_file) string_as_array = convert_string_to_array(input_string,temporary_nila_file) modified_array = [] string_as_array.each do |line| modified_array << " "*tab_counter + line end return modified_array.join end def fix_newlines(file_contents) def extract_blocks(file_contents) javascript_regexp = /(if |while |function |function\()/ 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" } modified_file_contents = file_contents.dup code_blocks = [] starting_index = starting_line_indices[0] 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" } starting_index = starting_line_indices[0] 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 javascript_regexp = /(if |while |function |function\()/ locations = [] javascript_file_contents = reset_tabs(javascript_file_contents) joined_file_contents = javascript_file_contents.join code_block_starting_locations = find_all_matching_indices(joined_file_contents,javascript_regexp) code_block_ending_locations = find_all_matching_indices(joined_file_contents,"}") combined_location = [code_block_starting_locations,code_block_ending_locations.dup].flatten.sort self_invoking_function_extract = joined_file_contents[code_block_starting_locations[0]..code_block_ending_locations[-1]] self_invoking_function_array = convert_string_to_array(self_invoking_function_extract,temporary_nila_file) combined_location.delete_at(0); combined_location.delete_at(-1); code_block_ending_locations.delete_at(-1); code_block_starting_locations.delete_at(0) modified_self_invoking_array = self_invoking_function_array.dup for x in 1...self_invoking_function_array.length-1 modified_self_invoking_array[x] = " " + self_invoking_function_array[x] end modified_self_invoking_array[-1] = "\n\n" + modified_self_invoking_array[-1] nested_elements = [] nested_indices = [] modified_starting_locations = code_block_starting_locations.dup while code_block_ending_locations.length > 0 matching_location = combined_location[combined_location.index(code_block_ending_locations[0])-1] combined_location.delete(matching_location) location_among_start_locations = code_block_starting_locations.index(matching_location) if location_among_start_locations == 0 locations << [[matching_location,combined_location[combined_location.index(code_block_ending_locations[0])]]] else nested_elements << [matching_location,combined_location[combined_location.index(code_block_ending_locations[0])]] nested_indices << modified_starting_locations.index(matching_location) end combined_location.delete(code_block_ending_locations[0]) code_block_ending_locations.delete_at(0) code_block_starting_locations.delete(matching_location) end nested_indices.each_with_index do |loc,index| begin locations[loc-1] << nested_elements[index] rescue NoMethodError puts "The pretty printing process exited with errors!" end end modified_locations = [] locations.each do |loc| modified_locations << loc.sort end modified_joined_file_contents = joined_file_contents.dup modified_joined_file_contents = modified_joined_file_contents.sub(self_invoking_function_extract,modified_self_invoking_array.join) modified_locations.each do |location| soft_tabs_counter = 2 location.each do |sublocation| string_extract = joined_file_contents[sublocation[0]..sublocation[1]] string_extract_array = convert_string_to_array(string_extract,temporary_nila_file) if soft_tabs_counter > 1 string_extract_array[0] = " "*(soft_tabs_counter-1) + string_extract_array[0] string_extract_array[-1] = " "*(soft_tabs_counter-1) + string_extract_array[-1] end for x in 1...string_extract_array.length-1 string_extract_array[x] = " "*soft_tabs_counter + string_extract_array[x] end if soft_tabs_counter > 1 modified_joined_file_contents = modified_joined_file_contents.sub(previous_formatting(string_extract,soft_tabs_counter-1,temporary_nila_file),string_extract_array.join) else modified_joined_file_contents = modified_joined_file_contents.sub(string_extract,string_extract_array.join) end soft_tabs_counter += 1 end end file_id = open(temporary_nila_file, 'w') file_id.write(modified_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) return line_by_line_contents end def pretty_print_nila(input_file_contents) #Implementation is pending end def static_analysis(input_file_contents) #Implementation is pending end def create_self_invoking_function(input_file_contents) # A feature imported from Coffeescript. This makes all the function private by default # and prevents global variables from leaking. modified_file_contents = ["(function() {\n",input_file_contents,"\n}).call(this);"].flatten return modified_file_contents 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 in Nila 0.0.3.3. 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 = split_semicolon_seperated_expressions(file_contents) file_contents = compile_interpolated_strings(file_contents) file_contents,singleline_comments = replace_singleline_comments(file_contents) file_contents,named_functions,nested_functions = replace_named_functions(file_contents,temp_file) comments = [singleline_comments,multiline_comments] list_of_variables,file_contents = get_variables(file_contents,temp_file) file_contents = compile_arrays(file_contents) file_contents = compile_conditional_structures(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 = create_self_invoking_function(file_contents) file_contents = pretty_print_javascript(file_contents,temp_file) 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 nilac_version = "0.0.3.7" 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 [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." end on :v, :version, 'Output Nilac Version No' do puts nilac_version end on :r, :run=, 'Run Nila File', as:Array on :m, :buildmac=, 'Build Nilac for Linux/Mac/Rubygems',as:Array 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_name(file_path,".nila") + ".js" node_output = `node #{js_file_name}` puts node_output elsif opts[:buildmac] != nil file_path = Dir.pwd + "/bin/nilac.rb" create_mac_executable(file_path) puts "Build Successful!" end