Vim is incredibly powerful, but it has the downside of a steep learning curve. Once that is surmounted, however, it’s easy to do a lot of powerful tricks with it. Many of these are things that one sees in full-blown IDEs. My setup provides auto-completion, test suite management, build management, source control integration and a variety of other useful tricks. One of the things that I really appreciate about vim is its handy filtering ability, but most vim developers don’t seem to be aware of it. I’ll explain one way of using it, with a primitive java2perl filter.
Java, as you’ve probably noticed, is one of the most popular programming languages out there. Thus, if you are looking for a particular algorithm, there’s a good chance of a Java solution on the Web. However, manually transforming this into your language of choice can be tedious. Enter vim filters.
Save the following program somewhere in your path as reverse.pl and make it executable (chmod +x reverse.pl).
#!/usr/bin/perl
use strict;
use warnings;
my $string = do { local $/; <STDIN> }; # slurp STDIN
print scalar reverse $string;
A vim filter provides its data via STDIN and reads STDOUT and STDERR. Add the following line to your .vimrc:
vnoremap ,rv :!reverse.pl <cr> " only work in 'visual' mode
The ‘v’ in the mapping means the mapping only works in ‘visual’ mode. Now if you select a range of lines (try “{shift}V and use navigation keys to select a range) and type ‘,rv’, the entire text selection will be reversed (useless, I know, but it shows how a filter works).
In order for us to get a proper java2perl filter, we need to consider a few things. Since both Java and Perl are considered “Algol-style languages”, a straight-forward syntactic transformation is not terribly difficult. However, semantic transformation is tricky. For a simple example, the code to read a file’s contents in Java and Perl is radically different. As a result, while I had considered a full-blown lexer/parser solution, I realized that it would take so long and have so many edge cases that it wasn’t worth the trouble since I merely wanted to use the occasional algorithm written in Java. As many standard libraries in Java and Perl have no direct translations, I felt that a simplistic solution was fine and I could manually fix what I needed. Here’s the code I threw together:
#!/usr/bin/perl
use strict;
use warnings;
my $method = do { local $/; <STDIN> };
my $class = qr/[[:upper:]][[:word:]]*/; # by convention
my $type = join
'|' => qw/int char float byte short long double boolean/,
$class;
my $var_name = qr/\b[[:word:]]+\b/;
my $declaration = qr/(?:$type(?:\[\])?)\s+$var_name/;
my $c_declaration = qr/($type(?:\[\])?)\s+($var_name)/; # capturing
my $var_list = qr/$declaration\s*(?:,\s*$declaration)*/;
my $return = "$type|void";
my $access_level = qr/public|private|protected/;
my $method_name = qr/[[:word:]]+/;
my $signature = qr/^
\s*
$access_level
\s+
(?:static\s+)?
(\w+) # return type
\s+
($method_name)
\s*
\(
\s*
($var_list)
\s*
\)
\s*
{ # the opening brace of the method
/mx;
my %seen_vars;
if ( $method =~ /$signature(.*)}\s*/s ) {
my ( $return_type, $method_name, $arguments, $method_body ) =
( $1, $2, $3, $4 );
my $method_start = "sub $method_name {\n";
my $method_end = 'void' eq $return_type ? " return;\n}" : "}";
my $args = " my ( ";
my @vars;
while ( $arguments =~ /$c_declaration/g ) {
push @vars => "\$$2";
$seen_vars{$2} = 1;
}
$args .= join ', ' => @vars;
$args .= ' ) = @_;';
$method_start .= "$args\n";
$method_body = munge_body($method_body);
print "$method_start$method_body$method_end";
}
sub munge_body {
my $body = shift;
# convert comments
$body =~ s{(\s*)//}{$1#}mg;
my @declarations;
# find all variable declarations
while ( $body =~ /($c_declaration)/g ) {
push @declarations => $1;
my $var = $3;
$seen_vars{$var} = 1;
}
# make the variable declarations
foreach my $declaration (@declarations) {
$declaration =~ /$c_declaration/;
my $var = $2;
$body =~ s/$declaration/my \$$var/g;
}
# just in case ...
delete $seen_vars{$_} foreach qw/ my local our /;
# prefix variables with '$'
foreach my $var (keys %seen_vars) {
$body =~ s/(?<!\$)$var\b/\$$var/g;
}
return $body;
}
It’s not pretty, but hey, this is Perl :)
Then I added my filter to my .vimrc.
vnoremap ,rw :!java2perl.pl <cr> " only work in 'visual' mode
The way this works is that I have to select the first line (the signature) of the method in visual mode and then navigate down to the end of the method. Since I’m working with line-drawing algorithms right now, I decided to try the Bresenham alorithm. Here’s the Java:
public void lineBresenham(int x0, int y0, int x1, int y1, Color color)
{
int pix = color.getRGB();
int dy = y1 - y0;
int dx = x1 - x0;
int stepx, stepy;
if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
dy <<= 1; // dy is now 2*dy
dx <<= 1; // dx is now 2*dx
raster.setPixel(pix, x0, y0);
if (dx > dy) {
int fraction = dy - (dx >> 1); // same as 2*dy - dx
while (x0 != x1) {
if (fraction >= 0) {
y0 += stepy;
fraction -= dx; // same as fraction -= 2*dx
}
x0 += stepx;
fraction += dy; // same as fraction -= 2*dy
raster.setPixel(pix, x0, y0);
}
} else {
int fraction = dx - (dy >> 1);
while (y0 != y1) {
if (fraction >= 0) {
x0 += stepx;
fraction -= dy;
}
y0 += stepy;
fraction += dx;
raster.setPixel(pix, x0, y0);
}
}
}
By selecting that in visual mode and applying my filter, I get this:
sub lineBresenham {
my ( $x0, $y0, $x1, $y1, $color ) = @_;
my $pix = $color.getRGB();
my $dy = $y1 - $y0;
my $dx = $x1 - $x0;
my $stepx, stepy;
if ($dy < 0) { $dy = -$dy; stepy = -1; } else { stepy = 1; }
if ($dx < 0) { $dx = -$dx; $stepx = -1; } else { $stepx = 1; }
$dy <<= 1; # $dy is now 2*$dy
$dx <<= 1; # $dx is now 2*$dx
raster.setPixel($pix, $x0, $y0);
if ($dx > $dy) {
my $fraction = $dy - ($dx >> 1); # same as 2*$dy - $dx
while ($x0 != $x1) {
if ($fraction >= 0) {
$y0 += stepy;
$fraction -= $dx; # same as $fraction -= 2*$dx
}
$x0 += $stepx;
$fraction += $dy; # same as $fraction -= 2*$dy
raster.setPixel($pix, $x0, $y0);
}
} else {
my $fraction = $dx - ($dy >> 1);
while ($y0 != $y1) {
if ($fraction >= 0) {
$x0 += $stepx;
$fraction -= $dy;
}
$y0 += stepy;
$fraction += $dx;
raster.setPixel($pix, $x0, $y0);
}
}
return;
}
That isn’t valid Perl, but only a couple of quick changes and I now have a working line drawing algorithm.
Naturally there’s lots more I could do to improve this feature, but my major need was to remove the bulk of the grunt work involved in transforming Java to Perl and this filter succeeded wonderfully.


Cool! Do you give 6 weeks quick intro classes in software development using perl and wim? I want a seat!!
Keep up the good work,
cheers
Excellent, but would it be worth filtering the modifiers for the method in a more resilient way? Ultimately you discard them, so you could change:
my $access_level = qr/public|private|protected/;
...
$access_level
\s+
(?:static\s+)?
Into something like:
my $access_and_modifiers = qr/public|protected|private|static|final|synchronized|strictfp/;
...
(?:$access_and_modifiers\s+)*
That way, the order of the modifiers and access level tokens does not matter, and it also accommodates the situation where no access level has been specified (default access). I may have missed a method appropriate modifier, but you get the idea.
Bit pedantic though :)
@Matthew: what you write sounds reasonable. To be fair, it's been a few years since I did serious Java programming and I know that my approach was rather limited. I'm happy with an 80% solution, but I'd be happy to see a more serious approach here.
I like it, i hope we can see something like this on GNOME so you can code in MONO and then just translate to "C" an get all the power. Have you ever seen Valac?