#!/usr/bin/perl -w
use strict;

my ($source, $replacement) = @ARGV;

if (!$replacement) {
  print "usage: ocaml-refactor.pl filename replacement\n";
  print "\
The idea is to first have a working .ml-file. Then
you rename an identifier (variable, function, type). This
results in code that will likely not compile. Then you enter
ocaml-refactor.pl source.ml thenewname and the script will
iterate the source (find error, replace with replacement)
until it finds no unbound identifiers. It might even result
in a working end result. Who knows.

NOTE: the original file WILL be modified, so be sure to have a backup
handy.
";
  exit 0;
}

sub replace_with {
  my ($file, $line, $begin, $end, $replacement) = @_;
  local *IN;
  local *OUT;
  open(IN, "$file");
  open(OUT, "> $file.refactor");
  my $n = 0;
  while (<IN>) {
    ++$n;
    if ($n == $line) {
      $_ = substr($_, 0, $begin) . $replacement .
	   substr($_, $end);
    }
    print OUT;
  }
  close(OUT);
  close(IN);
  rename("$file.refactor", "$file");
}

$ENV{SOURCE} = $source;

my $needs_compiling = 1;
$| = 1;
while ($needs_compiling) {
  $needs_compiling = 0;
  local *F;
  print "Compiling..\n";
  open(F, '(ocamlc -c "$SOURCE" 2>&1) |');
  while (<F>) {
    if (my ($line, $begin, $end) = 
	/^File .* line ([0-9]+), characters ([0-9]+)-([0-9]+):/) {
      my $error = <F>;
      if ($error =~ /^Unbound/) {
	print "Found error $error, fixing\n";
	$needs_compiling = 1;
	replace_with($source, $line, $begin, $end, $replacement);
	last;
      }
    }
    close(F);
  }
}

print "Done\n";
