Этот perl-скрипт выполняет хакерскую работу, делая некоторые предположения о структуре исходного файла. (Например: .hs
файл (не .lhs
), подписи находятся в строке, непосредственно предшествующей определениям, определения располагаются на одном уровне с левым полем и т. д.)
Он пытается обрабатывать (пропускать) комментарии, определения в стиле уравнений (с повторяющимися левыми частями) и типы, которые генерируют многострочный вывод в ghci
.
Без сомнения, многие интересные действительные случаи не обрабатываются должным образом. Сценарий не близок к реальному синтаксису Haskell.
Он невероятно медленный, так как запускает сеанс ghci
для каждой функции, которой требуется подпись. Он создает файл резервной копии File.hs.bak
, выводит найденные функции в stderr, а также сигнатуры для функций, в которых отсутствуют сигнатуры, и записывает обновленный исходный код в File.hs
. Он использует промежуточный файл File.hs.new
и имеет несколько проверок безопасности, чтобы избежать перезаписи содержимого мусором.
ИСПОЛЬЗУЙТЕ НА СВОЙ РИСК.
Этот сценарий может отформатировать ваш жесткий диск, сжечь ваш дом, выполнить unsafePerformIO и вызвать другие нежелательные побочные эффекты. На самом деле, скорее всего, так и будет.
Я чувствую себя таким грязным.
Протестировано на Mac OS X 10.6 Snow Leopard с парой моих собственных исходных файлов .hs
.
#!/usr/bin/env perl
use warnings;
use strict;
my $sig=0;
my $file;
my %funcs_seen = ();
my %keywords = ();
for my $kw qw(type newtype data class) { $keywords{$kw} = 1;}
foreach $file (@ARGV)
{
if ($file =~ /\.lhs$/)
{
print STDERR "$file: .lhs is not supported. Skipping.";
next;
}
if ($file !~ /\.hs$/)
{
print STDERR "$file is not a .hs file. Skipping.";
next;
}
my $ghciPreTest = `echo 1 | ghci $file`;
if ($ghciPreTest !~ /Ok, modules loaded: /)
{
print STDERR $ghciPreTest;
print STDERR "$file is not valid Haskell source file. Skipping.";
next;
}
my $module = $file;
$module =~ s/\.hs$//;
my $backup = "$file.bak";
my $new = "$module.New.hs";
-e $backup and die "Backup $backup file exists. Refusing to overwrite. Quitting";
open OLD, $file;
open NEW, ">$new";
print STDERR "Functions in $file:\n";
my $block_comment = 0;
while (<OLD>)
{
my $original_line = $_;
my $line = $_;
my $skip = 0;
$line =~ s/--.*//;
if ($line =~ /{-/) { $block_comment = 1;} # start block comment
$line =~ s/{-.*//;
if ($block_comment and $line =~ /-}/) { $block_comment=0; $skip=1} # end block comment
if ($line =~ /^ *$/) { $skip=1; } # comment/blank
if ($block_comment) { $skip = 1};
if (!$skip)
{
if (/^(('|\w)+)( +(('|\w)+))* *=/ )
{
my $object = $1;
if ((! $keywords{$object}) and !($funcs_seen{$object}))
{
$funcs_seen{$object} = 1;
print STDERR "$object\n";
my $dec=`echo ":t $1" | ghci $file | grep -A100 "^[^>]*$module>" | grep -v "Leaving GHCi\." | sed -e "s/^[^>]*$module> //"`;
unless ($sig)
{
print NEW $dec;
print STDERR $dec;
}
}
}
$sig = /^(('|\w)+) *::/;
}
print NEW $original_line;
}
close OLD;
close NEW;
my $ghciPostTest = `echo 1 | ghci $new`;
if ($ghciPostTest !~ /Ok, modules loaded: /)
{
print $ghciPostTest;
print STDERR "$new is not valid Haskell source file. Will not replace original (but you might find it useful)";
next;
} else {
rename ($file, $backup) or die "Could not make backup of $file -> $backup";
rename ($new, $file) or die "Could not make new file $new";
}
}
person
misterbee
schedule
23.01.2012
hs-lint
в Emacs будет автоматически применять предложения, еслиhs-lint-replace-without-ask
установлено вt
. Я не уверен, как ограничить его только подписями типов, но, безусловно, должен быть способ. И я публикую это только как комментарий, потому что это не решение EclipseFP. - person Jon Purdy   schedule 22.01.2012