require 'fileutils'

# A system command that prints commands to stdout before running them def pexec(str)

puts str
STDOUT.flush
system str
puts ""

end

desc “Bootstrap our version of Long Nguyen's C version of Meta-II” task :boot_c do

Dir.chdir "bootstrap" do
        puts "1. Build bootstrap compiler"
        pexec "gcc -o bootstrapped_c bootstrap.c"
        puts "2. Use the bootstrapped meta compiler to compile the meta_to_c.meta description of itself"
        pexec "./bootstrapped_c meta_to_c.meta meta_compiler_from_boostrapped_c.c"
        puts "3. Build the compiler we created from the meta description"
        pexec "gcc -o meta_c meta_compiler_from_boostrapped_c.c"
        puts "4. Now use the generated compiler to generate itself"
        pexec "./meta_c meta_to_c.meta meta_compiler.c"
        puts "5. Now ensure the compilers are exactly the same"
        pexec "diff meta_compiler_from_boostrapped_c.c meta_compiler.c"
end

end

# Non-empty Lines of Code calc def loc(filename)

File.readlines(filename).map {|l| l.strip.length==0?nil:l}.compact.length

end

def bootstrap_from_c(syntaxFile)

if syntaxFile =~ /^syntaxes/
        syntaxf = File.join("..", syntaxFile)
else
        syntaxf = File.join("..", "syntaxes", syntaxFile)
end
Dir.chdir("bootstrap") do
        puts "1. Build bootstrap compiler"
        pexec "gcc -o bootstrapped_c bootstrap.c"
        puts "2. Use the c meta compiler to compile the meta_to_ruby_minimal.meta description"
        pexec "./bootstrapped_c #{syntaxf} compile_to_ruby.c"
        puts "3. Build the stepping stone ruby compiler we created from the meta description"
        pexec "gcc -o meta_r compile_to_ruby.c"
        puts "4. Now use the generated stepping stone compiler to generate a ruby compiler for the ruby meta syntax"
        pexec "./meta_r #{syntaxf} meta_ruby_compiler_from_c.rb"
        puts "5. Run the generated ruby meta compiler to a ruby version"
        pexec "ruby -I. meta_ruby_compiler_from_c.rb #{syntaxf} > meta_ruby_compiler.rb"
        puts "6. Ruby version differ since it has single instead of double quotes around strings"
        #pexec "diff meta_ruby_compiler_from_c.rb meta_ruby_compiler.rb"
        puts "7. But we can generate again and ensure it is a meta compiler"
        pexec "ruby -I. meta_ruby_compiler.rb #{syntaxf} > meta_ruby_compiler2.rb"
        pexec "diff meta_ruby_compiler.rb meta_ruby_compiler2.rb"
        puts "8. One more round just to show off... :)"
        pexec "ruby -I. meta_ruby_compiler2.rb #{syntaxf} > meta_ruby_compiler3.rb"
        pexec "diff meta_ruby_compiler.rb meta_ruby_compiler3.rb"
        puts "Summary:\nCreated a #{loc('meta_ruby_compiler.rb')} line meta-II meta compiler from a #{loc(syntaxf)} line meta-II spec\n\n"
ensure_is_meta "meta_ruby_compiler.rb", syntaxf, "../bin/meta_compile"
end

end

# Bootstrap a syntax from the meta_compile compiler def bootstrap_from_ruby(syntaxFile, targetName = “tgen.rb”)

syntaxf    = File.join("syntaxes", syntaxFile)
# Assumes the ruby version has been bootstrapped from C and is installed as meta_compile
pexec "ruby bin/meta_compile #{syntaxf} > #{targetName}"
ensure_is_meta(targetName, syntaxf, targetName)

end

def diff_files(f1, f2)

File.read(f1) != File.read(f2)

end

def ensure_is_meta(generatedFile, specFile, saveAsTarget = nil)

pexec "ruby #{generatedFile} #{specFile} > t.rb"
pexec "ruby t.rb #{specFile} > t2.rb"
# Obviously we should now be able to go on and on... :)
pexec "ruby t2.rb #{specFile} > t3.rb"
begin
        if diff_files("t.rb", "t2.rb") || diff_files("t2.rb", "t3.rb")
                puts "ERROR: #{generatedFile} is NOT a meta compiler (generated from #{specFile})"
                exit(-1)
        else
                puts "YES #{generatedFile} is meta!!! (generated from #{specFile})"
                if saveAsTarget
                        FileUtils.mv("t2.rb", saveAsTarget) 
                        puts "Saved bootstrapped file as #{saveAsTarget}"
                end
                return true
        end
ensure
        FileUtils.rm_f Dir.glob("t*.rb")
end

end

def create_main_binary(sourceBinary)

FileUtils.cp sourceBinary, "bin/meta_compile"
FileUtils.chmod 0755, "bin/meta_compile"
puts "Created main binary in bin/meta_compile from #{sourceBinary}"

end

def bootstrap_with_stepping_stone(syntaxFile, target)

syntaxf    = File.join("syntaxes", syntaxFile)
stepstonef = File.join("syntaxes", "stepping_stone_" + syntaxFile)
pexec "ruby bin/meta_compile #{stepstonef} > tgen_stepstone.rb"
pexec "ruby tgen_stepstone.rb #{syntaxf} > #{target}"
ensure_is_meta(target, syntaxf, target)

end

desc “Bootstrap the Ruby meta compiler (uses the minimal syntax)” task :boot do

bootstrap_from_c "meta_to_ruby_minimal.meta"

end

desc “Bootstrap and set binary file permissions” task :bootstrap => :boot do

FileUtils.chmod 0755, "bin/meta_compile"

end

desc “Bootstrap the minimal Ruby meta compiler (from the Ruby meta compiler)” task :boot_minimal => :bootstrap do

bootstrap_from_ruby "meta_to_ruby_minimal.meta", "bin/metac_minimal"

end

desc “Make main gem binary from the minimal ruby meta compiler” task :make_bin_minimal => :boot_minimal do

create_main_binary "bin/metac_minimal"

end

desc “Ensure minimal ruby meta it is a meta compiler” task :ensure_meta_minimal => :make_bin_minimal do

ensure_is_meta "bin/meta_compile", "syntaxes/meta_to_ruby_minimal.meta"

end

desc “Bootstrap the readable meta compiler (from the Ruby meta compiler)” task :boot_readable => :make_bin_minimal do

bootstrap_from_ruby "meta_to_ruby.meta", "bin/metac_readable"

end

desc “Make main gem binary from the readable ruby meta compiler” task :make_bin_readable => :boot_readable do

create_main_binary "bin/metac_readable"

end

desc “Ensure readable ruby meta it is a meta compiler” task :ensure_meta_readable => :make_bin_readable do

ensure_is_meta "bin/meta_compile", "syntaxes/meta_to_ruby.meta"

end

desc “Bootstrap the meta compiler that accepts regexps” task :boot_regexp => :make_bin_minimal do

bootstrap_with_stepping_stone("meta_to_ruby_minimal_with_regexps.meta", "bin/metac_regexp")

end

def run_example(compiler, example)

puts "Compiling this input with #{compiler}:\n\n"
puts File.read(example)
puts "\ngives output:\n\n"
pexec "ruby #{compiler} #{example}"

end

def metac_regexp_run_examples(syntaxFile, *inputs)

pexec "ruby bin/metac_regexp #{syntaxFile} > tas.rb"
inputs.each do |i|
  run_example("tas.rb", "inputs/#{i}")
end

end

desc “Compile all inputs for the assignments syntax” task :ex_ass do

metac_regexp_run_examples "syntaxes/assignments.meta", "assignments.input1"

end

desc “Update line counts in README.template.md to make README.md” task :update => [:boot_minimal, :boot_regexp, :boot_readable] do

readme = File.read("README.template.md")
readme = readme.gsub("%%RMetaII_SPEC_LOC%%", loc('syntaxes/meta_to_ruby_minimal.meta').to_s)
readme = readme.gsub("%%RMetaII_COMPILER_LOC%%", loc('bin/metac_minimal').to_s)
readme = readme.gsub("%%RMetaII_READABLE_SPEC_LOC%%", loc('syntaxes/meta_to_ruby.meta').to_s)
readme = readme.gsub("%%RMetaII_READABLE_COMPILER_LOC%%", loc('bin/metac_readable').to_s)
File.open("README.md", "w") {|f| f.puts readme}

end

desc “Build the gem” task :build_gem => [:update, :make_bin_readable] do

Rake::Task["clean"].invoke
FileUtils.rm_f Dir.glob("meta_compile-*.gem")
pexec "gem build meta_compile.gemspec"

end

desc “Build and install gem” task :install_gem => [:build_gem] do

pexec "sudo gem install meta_compile*.gem"

end

desc “Deploy gem” task :deploy => :build_gem do

pexec "gem push meta_compile*.gem"

end

task :clean do

      Dir.chdir("bootstrap") do
        FileUtils.rm_f  %w{bootstrapped_c meta_compiler_from_boostrapped_c.c meta_compiler.c meta_ruby_compiler2.rb meta_ruby_compiler3.rb meta_ruby_compiler_from_c.rb compile_to_ruby.c meta_c meta_r}
end
FileUtils.rm_f Dir.glob("t*.rb")

end

task :clobber => [:clean] do

      Dir.chdir("bootstrap") do
        FileUtils.rm_f %w{meta_ruby_compiler.rb meta_compile*.gem}
      end
FileUtils.rm_f Dir.glob("meta_compile-*.gem")

end

task :default => :make_bin_readable