2009-11-13

Exing it up

I'm still working on translating Java Processing code to Scala.  I've gone through most of the basic Processing examples now.  To speed the process up a bit, I use a small set of Ex commands.  I load the Java code in a buffer, run :so ec (the name of the Ex file) and paste the text into a boilerplate Scala applet object.  This takes care of most of the common, simple changes and lets me concentrate on the more important aspects of translation.

To begin with, I like to change underlined identifiers, which some examples use, into droopyCamelCase such as foo_bar => fooBar.  I don't want to change certain constants like TWO_PI, though.  The command :%s/_\(\l\)/\u\1/gc does this for me.  If you're unfamiliar with Ex, this command means "in every line (%) search and replace (s) occurrencies of underline and a lowercase character (\l), which is stored as item #1 (\( ... \)) with that item (\1), translated into upper case (\u); do this for every occurence in the line (g), but ask first (c)".  If you are a Vim user, you're probably familiar with this, so I won't explain every command in detail in the following.

In most cases, I want to make structural changes by hand: it's a lot easier and more educating that way.  However, it is very handy to pre-translate the for structure (and also the switch structure, but I haven't gotten around to that yet).  I use two commands, one for cases where iteration includes the end value, and one for cases where it is excluded:

:%s/for\s*(\s*\i\+\s\+\(\i\+\)\s*=\s*\(\w\)[^;]*;[^<]*<=\s*\(\i\+\)[^;]*;\([^)]*\))/for (\1 <- \2 to \3 \/* TODO \4 *\/)/

:%s/for\s*(\s*\i\+\s\+\(\i\+\)\s*=\s*\(\w\)[^;]*;[^<]*<\s*\(\i\+\)[^;]*;\([^)]*\))/for (\1 <- \2 until \3 \/* TODO \4 *\/)/

Note that I just stick the third expression of the Java for (item #4) into a comment -- in case it's just a ++foo or the equivalent the action is implied in the Scala for and I just delete the comment, and in other cases I rewrite as required.

Java and Scala has different syntaxes for declarations: Java uses type name, while Scala uses name: type (like Pascal).  Also, Scala requires you to use the keywords val, var, and def for constants, variables, and methods, respectively (other declarations usually don't use them).  I use a rule of thumb here.  If the declaration is the first thing on the line, I assume it's a constant declaration and rewrite it using this command: :%s/^\(\s*\)\<float\>\s\+\(\w\+\)/\1val \2: Float/g (for float, which is used a lot in Processing code).  In other cases, I use :%s/\<float\>\s\+\(\w\+\)/\1: Float/g.  Currently, I only have commands for ints, floats, and booleans and translate other declarations manually.  If a declared identifier is later used for assignment, I try to restructure the code to be immutable or else just change the val to a var.

As for methods, in Processing they seem to be typed void as a rule.  A few methods, like setup and draw, are inherited from PApplet and need to be explicitly overridden.  In other cases, I just change the void to a def.  The commands are :%s/void \<\(setup\|draw\)\>/override def \1/ and :%s/void/def/.

Now I want to clear out unnecessary separators like semicolons and empty parentheses: :%s/;\s*$// and :%s/(\s*)// take care of (most of) those.  Some lines have an ending comment, which I like to rewrite (code; // comment  =>  // comment<newline>code), but I do that manually and then the semicolon is useful to position the cursor at the point of separation.

Finally, non-whole values are interpreted as Doubles by the Scala compiler, so I need to add an f to them unless it's already there: :%s/\(\.\d\+\)\([^f]\|$\)/\1f\2/g.

Many of the short example programs don't need much more work after these automatic translations.  I might add a few more rules in the future, but it's important to remember that the point of this is to simplify the translation procedure.  Simple, rule-of-thumb translations are good candidates for this kind of automatic processing, but anything that requires analysis is better to do manually.  The for commands are arguably too long, but they still do very simple substitutions and are very helpful.

No comments:

Post a Comment