require 'voodoo'

generator = Voodoo::CodeGenerator.get_generator

generator.instance_eval do
  import :printf, :putchar, :puts

  align_data
  add_data_label :string_0
  add_data [:string, "No more bottles of beer on the wall, " +
                     "no more bottles of beer.\n" +
                     "Go to the store and buy some more, " +
                     "99 bottles of beer on the wall.\x00"]

  align_data
  add_data_label :no_more_beer
  add_data [:string, "no more bottles of beer\x00"]

  align_data
  add_data_label :one_bottle
  add_data [:string, "1 bottle of beer\x00"]

  align_data
  add_data_label :beer_format
  add_data [:string, "%d bottles of beer\x00"]

  align_data
  add_data_label :on_the_wall_format
  add_data [:string, " on the wall%s\x00"]

  align_data
  add_data_label :comma
  add_data [:string, ", \x00"]

  align_data
  add_data_label :period
  add_data [:string, ".\n\x00"]

  align_data
  add_data_label :take_one
  add_data [:string, ".\nTake one down and pass it around, \x00"]

  align_function
  add_function_label :print_beer
  add_function [:n],
    [:ifeq, [:n, 0],
     # if n is equal to zero ...
     [[:'tail-call', :printf, :no_more_beer]],
     # else
     [[:ifeq, [:n, 1],
       # if n is equal to one ...
       [[:'tail-call', :printf, :one_bottle]],
       # else
       [[:'tail-call', :printf, :beer_format, :n]]]]]

  align_function
  add_function_label :bottles
  add_function [:n],
    [:let, :m, :sub, :n, 1],
    [:ifeq, [:n, 0],
     # if n is equal to zero ...
     [[:call, :puts, :string_0],
      [:return, 0]],
     # else
     [[:call, :print_beer, :n],
      [:call, :printf, :on_the_wall_format, :comma],
      [:call, :print_beer, :n],
      [:call, :printf, :take_one],
      [:call, :print_beer, :m],
      [:call, :printf, :on_the_wall_format, :period],
      [:call, :putchar, 10],
      [:'tail-call', :bottles, :m]]]

  align_function
  export :main
  add_function_label :main
  add_function [:argc, :argv],
    [:call, :bottles, 99],
    [:return, 0]
end

File.open('99bottles.o', 'w') { |file| generator.write file }
