DrJava/HJ Born

I have been able to merge Vincent’s and Jarred’s changes into the DrJava trunk to create a version of DrJava/HJ that can compile and run Habanero Java (HJ) programs. Most importantly, there is a version where both HJ and DrJava are in one 20 MB file. Please try it out: drjava-hj.jar

DrJava/HJ Logo

I have identified a change that needs to be made to the HJ Runtime in order to integrate it with DrJava. It is small and does not affect the performance or execution of HJ when it is run independently from DrJava.

The class loader that HJ uses to find classes it is running has to be changed. DrJava has a dynamic class path, depending on the files that are open, the configuration of the project, and the global preferences. If HJ is to find the classes that DrJava has compiled, HJ needs to use the class loader DrJava provides. DrJava passes this class loader to its runtimes as “thread context class loader”, which “provides a way to pass an ‘intended classloader parent’ into a framework without explicitly needing to pass it.” [source]

The thread context class loader can be queried using Thread.currentThread().getContextClassLoader() and needs to be passed wherever a user class is loaded using Class.forName. I found four such calls to Class.forName in the HJ runtime. The nice thing about the thread context class loaders is that, unless they are set, they default to the system class loader. As a result, unless DrJava (or some other application using the HJ runtime) set the thread context class loader to tell HJ “use this class loader to find my classes”, everything is just as before.

Posted in DrJava, Research | Leave a comment

Print This Print This   Email This Email This

Mint on the Mac

I guess I’m a bit behind the technology curve. The MacBook that I’m using as one of my development machines is one of the original white Intel MacBooks with a Core Duo CPU (not Core 2 Duo). It’s a 32-bit machine, and Apple doesn’t offer Java 6 for 32-bit computers.

Mint, however, requires a version of Java 6, which is why we recommended using SoyLatte to run Mint. That comes with all kinds of inconveniences because SoyLatte uses X11 for its GUIs, which means DrJava needs to run under X11.

Yesterday I tested Mint and DrJava with Mint using Apple’s Java SE 6.0 Release 1 Developer Preview 6 (file name: javase6release1dp6.dmg), which I still had floating around and which is the last version of Apple’s Java 6 that still runs on 32-bit Macs. It works! SoyLatte is only required if you don’t have a version of Java 6 (either Apple’s official version on 64-bit Macs, or Apple’s Java SE 6.0 Release 1 Developer Preview 6 on 32-bit Macs) on your Mac.

I have updated the instructions on how to install Java Mint on the Mac and how to run DrJava with Mint accordingly.

(Re-posted from The Java Mint Blog.)

Posted in Mint | Leave a comment

Print This Print This   Email This Email This

Reflection-Based S-Expression Parser

I’m really quite proud of this little reflection-based S-expression parser that I wrote for our GPCE Mint tutorial.

We wanted to have a parser so we don’t have to construct our ASTs using Java code. The problem was that we’ll probably have ten different mini-languages, and we didn’t want to write a parser for each language. Reflection was the answer, of course.

For this parser to work, you need to define the base class of the class hierarchy (e.g. Exp) and the subclasses as static nested classes inside the same outer class (e.g. all inside UnstagedLint).

You then simply specify the base class, and the parser will search for the subclasses. The names of the S-expressions are the simple names of the subclasses (e.g. Add and Int if there are Add and Int subclasses).

When encountering an S-expression, the parser will try all of the constructors of the corresponding class. As arguments for a constructor, the parser can process all primitive types, the boxed types, strings, recursive occurrences of the base class (e.g. Add containing two Exp instances), as well as other class hierarchies, which are parsed using subparsers.

These subparsers work the same way the main parser works. For example, if a Val constructor needs a Value argument, and there is a subparser registered for the Val hierarchy, the main parser will delegate to that subparser. Here’s an example:

1
2
3
4
DataTypes.Exp e =
    new LintParser<DataTypes.Exp>(DataTypes.Exp.class)
    .addSubParser(new LintParser<DataTypes.Value>(DataTypes.Value.class))
    .parse("(Add (Val (IntValue 1)) (Val (IntValue 2)))");

This creates a parser for expressions of class DataTypes.Exp, and it registers a subparser for expressions of class DataTypes.Value. Then it parses the string (Add (Val (IntValue 1)) (Val (IntValue 2))). The (IntValue 1) and (IntValue 2) substrings are parsed using the subparser.

It’s really quite elegant. Especially the ease of integrating the subparsers surprised me. Here’s the parser in full.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
package parser;

import java.lang.reflect.*;
import java.util.*;

/**
 * A reflection-based S-expression parser returning an expression of type E.
 * Written by Mathias Ricken and Edwin Westbrook.
 */

public class LintParser<E> {
    /** Convenience method to parse string s into an expression of class c,
      * using the specified subparsers as help, if the parser encounters non-primitive,
      * non-string arguments to S-expressions not within the class hierarcy under class c.
      * @param c class of the expression
      * @param s string to parse
      * @param subParsers subparsers for non-primitive, no-string values
      * @return expression of class c */

    public static <T> T parse(Class<T> c, String s, LintParser<?>... subParsers) {
        LintParser<T> p = new LintParser<T>(c);
        for(LintParser<?> sp: subParsers) {
            p.addSubParser(sp);
        }
        return p.parse(s);
    }
   
    /** Exception being thrown if the string cannot be parsed. */
    public static class ParseException extends RuntimeException { }
   
    /** The class of the expression (e.g. lint1_arithmetic.UnstagedLint.Exp). */
    private Class<E> _expClass;
   
    /** The class enclosing the expression classes (e.g. lint1_arithmetic.UnstagedLint). */
    private Class<?> _enclosingClass;
   
    /** A map from S-expression names to classes (e.g. Int -> lint1_arithmetic.UnstagedLint.Int). */
    private HashMap<String,Class<? extends E>> _classes =
        new HashMap<String,Class<? extends E>>();
   
    /** A map from classes for which subparsers have been registered to the subparsers. */
    private HashMap<Class<?>,LintParser<?>> _subParsers =
        new HashMap<Class<?>,LintParser<?>>();
   
    /** Create a new parser for expressions of class expClass.
      * @param expClass the class of the expressions to be parsed */

    public LintParser(Class<E> expClass) {
        _expClass = expClass;
        _enclosingClass = _expClass.getEnclosingClass();
        // find all concrete, static subclasses of expClass contained in the same enclosing class
        for(Class<?> c: _enclosingClass.getDeclaredClasses()) {
            if (((c.getModifiers() & Modifier.ABSTRACT)==0) &&
                ((c.getModifiers() & Modifier.STATIC)!=0)) {
                try {
                    Class<? extends E> contained = c.asSubclass(_expClass);
                    _classes.put(contained.getSimpleName(), (Class<? extends E>)contained);
                    println(contained.getSimpleName());
                }
                catch(ClassCastException cce) { /* skip */ }
            }
        }
    }
   
    /** Add a subparser for expressions of type S. Return this parser (not the subparser!)
      * for method chaining.
      * @param p subparser for expressions of type S
      * @return this parser (for expressions of type E) */

    public <S> LintParser<E> addSubParser(LintParser<S> p) {
        _subParsers.put(p._expClass, p);
        return this;
    }    
   
    /** Parse the string.
      * @param s the string to be parsed
      * @return the expression of type E */

    public E parse(String s) {
        println("parse '"+s+"'");
        RestoreStringTokenizer st = new RestoreStringTokenizer(s.trim());
        return parse(st);
    }
   
    /** Parse the tokens in the tokenizer.
      * @param s the tokenizer with the tokens
      * @return the expression of type E */

    protected E parse(RestoreStringTokenizer s) {
        // position to restore everything
        final int sPos = s.getPosition();
       
        // read (
        parseWhitespace(s);
        String word = s.nextToken();
        println("word: '"+word+"'");
        if (!word.equals("(")) {
            s.restorePosition(sPos);
            throw new ParseException();
        }
       
        // read S-expression name
        parseWhitespace(s);
        word = s.nextToken();
        println("word: '"+word+"'");
        if (!_classes.containsKey(word)) {
            // don't know what that is, restore
            s.restorePosition(sPos);
            throw new ParseException();
        }
       
        // known subclass of E
        Class<? extends E> c = _classes.get(word);
        println("Class: "+c.getSimpleName());        
        parseWhitespace(s);
       
        // position to restore after trying out a constructor
        final int sTryCtorPos = s.getPosition();
       
        Constructor<? extends E> ctor;
        for(Constructor<?> ctor2: c.getDeclaredConstructors()) {
            println("\ttrying ctor "+ctor2);
           
            // this is necessary since c.getDeclaredConstructors() returns Constructor<?>
            // but we want Constructor<? extends E>
            try { ctor = c.getConstructor(ctor2.getParameterTypes()); }
            catch(NoSuchMethodException nsme) { throw new AssertionError("Should never happen."); }
           
            // try to parse the arguments for this constructor
            Object[] args = new Object[ctor.getParameterTypes().length];
            int argIndex = 0;
            try {
                for(Class<?> paramC: ctor.getParameterTypes()) {
                    // primitive types and their boxed types
                    if ((paramC==int.class) || (paramC==Integer.class)) {
                        args[argIndex] = parseLeaf(s,Integer.class);
                    }
                    else if ((paramC==boolean.class) || (paramC==Boolean.class)) {
                        args[argIndex] = parseLeaf(s,Boolean.class);
                    }
                    else if ((paramC==long.class) || (paramC==Long.class)) {
                        args[argIndex] = parseLeaf(s,Long.class);
                    }
                    else if ((paramC==double.class) || (paramC==Double.class)) {
                        args[argIndex] = parseLeaf(s,Double.class);
                    }
                    else if ((paramC==float.class) || (paramC==Float.class)) {
                        args[argIndex] = parseLeaf(s,Float.class);
                    }
                    else if ((paramC==byte.class) || (paramC==Byte.class)) {
                        args[argIndex] = parseLeaf(s,Byte.class);
                    }
                    else if ((paramC==short.class) || (paramC==Short.class)) {
                        args[argIndex] = parseLeaf(s,Short.class);
                    }
                    // char or Character
                    else if ((paramC==char.class) || (paramC==Character.class)) {
                        // parse as string
                        Object temp = parseLeaf(s,String.class);
                        // must be exactly one character
                        if (temp.toString().length()!=1) throw new ParseException();
                        args[argIndex] = new Character(temp.toString().charAt(0));
                    }                    
                    // strings
                    else if (paramC==String.class) {
                        args[argIndex] = parseLeaf(s,String.class);
                    }
                    // recursively parse expressions of type E
                    else if (_expClass.equals(paramC)) {
                        args[argIndex] = parse(s);
                    }
                    // try to use a subparser
                    else if (_subParsers.containsKey(paramC)) {
                        // try one of the subparsers
                        args[argIndex] = _subParsers.get(paramC).parse(s);
                    }                    
                    else {
                        // don't know what that is
                        // restore happens below
                        throw new ParseException();
                    }
                    ++argIndex;
                }
            }
            catch(ParseException pe) {
                // this constructor didn't work out, we need to restore and try another constructor
                s.restorePosition(sTryCtorPos);
                // continue with next constructor
                continue;
            }
            try {
                // we read all values required for this constructor
                // make sure that the next token is )
                parseWhitespace(s);
                word = s.nextToken();
                println("word: '"+word+"'");
                if (!word.equals(")")) {
                    // it wasn't ), we need to restore and try another constructor
                    s.restorePosition(sTryCtorPos);
                    // continue with next constructor
                    continue;
                }
                parseWhitespace(s);
               
                // successfully used this constructor
                println("new "+ctor.getDeclaringClass().getSimpleName()+" "+
                        java.util.Arrays.toString(args));
                E e = (E)ctor.newInstance(args);
                return e;
            }
            catch(Exception e) {
                // something went wrong using this constructor, we need to restore and try another
                s.restorePosition(sTryCtorPos);
                // continue with next constructor
                continue;
            }
        }
       
        s.restorePosition(sPos);
        throw new ParseException();
    }
   
    /** Parse a leaf of class c, which must have a unary constructor taking a String, from
      * the tokenizer s.
      * @param s tokenizer from which to parse
      * @param c the class, which has a unary constructor taking a String, for that we want to create a value
      * @return parsed value of class c */

    protected Object parseLeaf(RestoreStringTokenizer s, Class<?> c) {
        // position so we can undo this attempt to parse
        final int sPos = s.getPosition();
       
        String word = null;
        try {
            // get the unary constructor taking String
            Constructor ctor = c.getDeclaredConstructor(String.class);
           
            // skip whitespace, get the string, skip whitespace
            parseWhitespace(s);
            word = s.nextToken();
            println("word: '"+word+"'");
            Object o = ctor.newInstance(word);
            parseWhitespace(s);
           
            return o;
        }
        catch(NoSuchMethodException nsme) {
            // something went wrong, restore and abort
            s.restorePosition(sPos);
            throw new ParseException();
        }
        catch(InstantiationException ie) {
            // something went wrong, restore and abort
            s.restorePosition(sPos);
            throw new ParseException();
        }
        catch(IllegalAccessException iae) {
            // something went wrong, restore and abort
            s.restorePosition(sPos);
            throw new ParseException();
        }
        catch(InvocationTargetException ite) {
            // something went wrong, restore and abort
            s.restorePosition(sPos);
            throw new ParseException();
        }
    }
   
    /** Parse whitespace. Stop before the next non-whitespace token, or when there are no
      * more tokens.
      * @param s tokenizer from which to parse whitespace */

    protected void parseWhitespace(RestoreStringTokenizer s) {
        String word;
        int sPrevPos;
        while(s.hasMoreTokens()) {
            sPrevPos = s.getPosition();
            word = s.nextToken();
            if (!word.trim().equals("")) {
                s.restorePosition(sPrevPos);
                break;
            }
        }
    }
   
    /** Debug method to print, comment System.out.println call out to disable debug printing */
    public static void println(Object o) {
        // System.out.println(o.toString());
    }
   
    /** This tokenizer stores all read tokens in a stack so they can easily be
      * restored. This isn't as memory as it could be, but it's good enough for
      * small examples. */

    public static class RestoreStringTokenizer extends StringTokenizer {
        /** Stack of read tokens. */
        private Stack<String> _read = new Stack<String>();
        /** Stack of restored tokens. */
        private Stack<String> _restored = new Stack<String>();
        /** Create a new string tokenizer that can restore positions. */
        public RestoreStringTokenizer(String s) { super(s," ()",true); }
        /** Return the current position. */
        public int getPosition() { return _read.size(); }
        /** Rewind to a previous position. This only goes backward, not forward. */
        public void restorePosition(int pos) {
            while(_read.size()>pos) {
                _restored.push(_read.pop());
            }
        }
        // overridden methods from StringTokenizer
        public int countTokens() { return _restored.size() + super.countTokens(); }
        public boolean hasMoreTokens() { return (_restored.size()>0) || super.hasMoreTokens(); }
        public boolean hasMoreElements() { return hasMoreTokens(); }
        public String nextToken() {
            String token = (_restored.size()>0) ? _restored.pop() : super.nextToken();
            _read.push(token);
            return token;
        }
        public Object nextElement() { return nextToken(); }
        public String nextToken(String delim) {
            if (_restored.size()>0) return _restored.pop();
            return super.nextToken(delim);
        }
    }
       
    public static void main(String[] args) {
        lint2_cond.UnstagedLint.Exp e = parse
            (lint2_cond.UnstagedLint.Exp.class,"(Ifz (Int 1) (Int 10) (Mul(Int 3)(Add(Int 5)(Int 10))))");
        System.out.println(new lint2_cond.UnstagedLint.Program(e).peval(lint2_cond.UnstagedLint.env0));
       
        lint.DataTypes.Value v = parse(lint.DataTypes.Value.class, "(IntValue 1)");
        System.out.println(v);
       
        lint.DataTypes.Exp e2 =
            new LintParser<lint.DataTypes.Exp>(lint.DataTypes.Exp.class)
            .addSubParser(new LintParser<lint.DataTypes.Value>(lint.DataTypes.Value.class))
            .parse("(Add (Val (IntValue 1)) (Val (IntValue 2)))");
        System.out.println(new lint.DataTypes.Program(e2).peval(lint.DataTypes.env0, lint.DataTypes.fenv0));

        lint.DataTypes.Exp e3 =
            LintParser.parse(lint.DataTypes.Exp.class, "(Add (Val (IntValue 1)) (Val (IntValue 2)))",
                             new LintParser<lint.DataTypes.Value>(lint.DataTypes.Value.class));
        System.out.println(new lint.DataTypes.Program(e3).peval(lint.DataTypes.env0, lint.DataTypes.fenv0));

    }
}

Here is the definition of a simple language for arithmetic expressions that uses the parser:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package lint1_arithmetic;

public class UnstagedLint {
   
    /*
     type exp = Int of int
     | Var of string
     | Add of exp * exp
     | Sub of exp * exp
     | Mul of exp * exp
     | Div of exp * exp
     type def = Definition of string * int
     type prog = Program of def list * exp
     */

   
    public static interface Exp {
        public int eval(Env e);
    }
   
    public static class Int implements Exp {
        private int _value;
        public Int(int value) {
            _value = value;
        }
        public int eval(Env e) {
            return _value;
        }
    }
   
    public static class Var implements Exp {
        private String _s;
        public Var(String s) {
            _s = s;
        }
        public int eval(Env e) {
            return e.get(_s);
        }
    }
   
    public static abstract class BinOp implements Exp {
        protected Exp _left, _right;
        public BinOp(Exp left, Exp right) {
            _left = left;
            _right = right;
        }
    }
   
    public static class Add extends BinOp {
        public Add(Exp left, Exp right) {
            super(left, right);
        }
        public int eval(Env e) {
            return _left.eval(e) + _right.eval(e);
        }
    }
   
    public static class Sub extends BinOp {
        public Sub(Exp left, Exp right) {
            super(left, right);
        }
        public int eval(Env e) {
            return _left.eval(e) - _right.eval(e);
        }
    }
   
    public static class Mul extends BinOp {
        public Mul(Exp left, Exp right) {
            super(left, right);
        }
        public int eval(Env e) {
            return _left.eval(e) * _right.eval(e);
        }
    }
   
    public static class Div extends BinOp {
        public Div(Exp left, Exp right) {
            super(left, right);
        }
        public int eval(Env e) {
            return _left.eval(e) / _right.eval(e);
        }
    }
   
    /*
     exception EnvironmentException
     let env0 = fun x -> raise EnvironmentException
     let fenv0 = env0
     let ext env x v = fun y -> if x=y then v else env y
     */

   
    public static class EnvironmentException extends RuntimeException { }
   
    // environment; implemented as a function object from String to Exp
    public static interface Env {
        public int get(String y);
    }
    public static final Env env0 = new Env() {
        public int get(String s) { throw new EnvironmentException(); }
    };
   
    public static Env ext(final Env env, final String x, final int v) {
        return new Env() {
            public int get(String y) {
                if (x.equals(y)) return v; else return env.get(y);
            }
        };
    }
   
    public static class Definition {
        private String _name;
        private int _v;
        public Definition(String name, int v) {
            _name = name;
            _v = v;
        }
        public String name() { return _name; }
        public int value() { return _v; }
    }

    public static class Program {
        public Definition[] _defs;
        public Exp _body;
        public Program(Exp body, Definition... defs) {
            _defs = defs;
            _body = body;
        }
       
        public int peval(Env env) {
            return peval(env,0);
        }
       
        private int peval(final Env env, int defIndex) {
            // match p with
            if (_defs.length<=defIndex) {
                //     Program ([],e) -> eval e env
                return _body.eval(env);
            }
            else {
                //    |Program (Definition (n,v)::tl,e) -> peval (Program(tl,e)) (ext env n v)
                final Definition d = _defs[defIndex];
                return peval(ext(env, d.name(), d.value()),defIndex+1);
            }
        }
    }
   
    /*
     let rec eval e env fenv =
     match e with
     Int i -> i
     | Var s -> env s
     | Add (e1,e2) -> (eval e1 env fenv)+(eval e2 env fenv)
     | Sub (e1,e2) -> (eval e1 env fenv)-(eval e2 env fenv)
     | Mul (e1,e2) -> (eval e1 env fenv)*(eval e2 env fenv)
     | Div (e1,e2) -> (eval e1 env fenv)/(eval e2 env fenv)
     
     let rec peval p env =
     match p with
     Program ([],e) -> eval e env
     |Program (Definition (s1,i1)::tl,e) -> peval (Program(tl,e)) (ext env s1 i1)
     
     */

   
    public static Program term10times20plus30 = new Program
        (new Add(new Mul(new Var("x"), new Var("y")), new Int(30)),
         new Definition("x", 10),
         new Definition("y", 20));

    public static Program parsedTerm10times20plus30 = new Program
        (parser.LintParser.parse(Exp.class, "(Add (Mul (Var x) (Var y)) (Int 30))"),
         new Definition("x", 10),
         new Definition("y", 20));

    public static Program termWhatX = new Program
        (new Var("x"));

    public static Program parsedTermWhatX = new Program
        (parser.LintParser.parse(Exp.class, "(Var x)"));
       
    public static void main(String[] args) {
        int i = term10times20plus30.peval(env0);
        System.out.println("term10times20plus30 = "+i);
       
        i = parsedTerm10times20plus30.peval(env0);
        System.out.println("parsedTerm10times20plus30 = "+i);
       
        try {
            i = termWhatX.peval(env0);
            System.out.println("termWhatX = "+i);
            throw new AssertionError("This should throw an EnvironmentException");
        }
        catch(EnvironmentException ee) { System.out.println("termWhatX threw "+ee); /* expected */ }

        try {
            i = parsedTermWhatX.peval(env0);
            System.out.println("parsedTermWhatX = "+i);
            throw new AssertionError("This should throw an EnvironmentException");
        }
        catch(EnvironmentException ee) { System.out.println("parsedTermWhatX threw "+ee); /* expected */ }
    }
}
Posted in Mint | Leave a comment

Print This Print This   Email This Email This

Bookmark Google Calendar Searches

I think I have finally figured out how how to bookmark Google Calendar searches. The problem was that the search parameters did not seem to be passed using URL “get” parameters. The Google Calendar URL was always just

https://www.google.com/calendar/render
and the search parameters never made it into a bookmark.

I just experimented a bit by passing q=blabla arguments, and doing that seems to work. I can specify to just search my calendar using src=username%40gmail.com. For example, this URL can be bookmarked to search my calendar for “opera OR symphony OR concert OR theater OR theatre”:

1
https://www.google.com/calendar/render?src=username%40gmail.com&q=opera%20OR%20concert%20OR%20symphony%20OR%20theater%20OR%20theatre

Replace username%40gmail.com with your GMail address. Use %40 instead of the “at” sign (@) and %20 instead of a space.

Posted in Uncategorized | Leave a comment

Print This Print This   Email This Email This

String Pool Interning Saves the Weakly Separable Day

I just took a swim in the string pool. Who would have thought that interning strings would be so useful for weak separability in Mint?

I knew before that we had some problems calling String.equals in a separable method, like the Env.get(String y) method that does an environment look-up, because String.equals wasn’t declared separable itself. That’s why I used the == operator in the initial Lint interpreter I wrote for the PLDI 2010 paper:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static separable Env ext(final Env env,
                                final String x,
                                final Code<Integer> v) {
    return new Env() {
        public separable Code<Integer> get(String y) {
            // error: if (x.equals(y))
            if (x==y)
                return v;
            else
                return env.get(y);
        }
    };
}

This wasn’t a problem because we didn’t have a parser and were creating our ASTs using hand-written Java code. The variable names are string constants, which are always interned:

1
2
3
4
public static Program term10times20plus30 = new Program
    (new Add(new Mul(new Var("x"), new Var("y")), new Int(30)),
     new Definition("x", <|10|>),
     new Definition("y", <|20|>));

Tonight, I wrote a reflection-based S-expression parser, and now the variable names are substrings of a longer string:

1
2
3
4
public static Program parsedTerm10times20plus30 = new Program
    (parser.LintParser.parse(Exp.class, "(Add (Mul (Var x) (Var y)) (Int 30))"),
     new Definition("x", <|10|>),
     new Definition("y", <|20|>));

Substrings aren’t interned automatically, and the comparison using == fails. Fortunately, I can simply intern the strings when I create the Var AST nodes and the Definition variable bindings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static class Var implements Exp {
    private String _s;
    public Var(String s) {
        _s = s.intern(); // must intern here, so we can use == in the ext method below
    }
    public separable Code<Integer> eval(Env e) {
        return e.get(_s);
    }
}
public static class Definition {
    private String _name;
    private Code<Integer> _v;
    public Definition(String name, Code<Integer> v) {
        _name = name.intern(); // must intern here, so we can use == in the ext method above
        _v = v;
    }
    public separable String name() { return _name; }
    public separable Code<Integer> value() { return _v; }
}

This was a whole lot simpler and cleaner than making some kind of exception for String.equals.

Posted in Mint | Leave a comment

Print This Print This   Email This Email This

New Mint Release: r15716

As mentioned before, Eddy and I discovered a problem with type variables in code generated by the Mint compiler. We have now fixed this problem in the new release of Mint and DrJava with Mint: August 30, 2010 (r15716). The latest release is, as always, available from the Mint implementation page:

The problem occurred when the programmer used a type variable inside a bracket. An example of this would be a generic method like this:

1
2
3
4
public separable <X> Code<X> fun(Code<X> c1, Code<X> c2) {
return <| ( `(lfTest.eval(e,f).booleanCodeValue()) ?
              `c2 : `c1 )  |>;
}

This caused Mint to generate 2nd stage code that contained the type variable X unbound. Unfortunately, the types are erased, and there is no way to find out what type X actually refers to at runtime, e.g. by writing something like X.class (this generates the Java compiler error “cannot select from a type variable”).

To get around this problem, we now require a final instance of type Class<X> to be in scope for every type variable X. For example, in the generic method above, there is a type variable X that is being used in the bracket. Therefore, we now have to have a final instance of Class<X> somewhere in scope, for example as a method parameter.

1
2
3
4
5
public separable <X> Code<X> fun(Code<X> c1, Code<X> c2,
                                 final Class<X> xc) {
return <| ( `(lfTest.eval(e,f).booleanCodeValue()) ?
              `c2 : `c1 )  |>;
}

That’s all that is necessary. The variable xc is not actually used in the code, it just needs to be in scope.

(Re-posted from The Java Mint Blog.)

Posted in Mint | Leave a comment

Print This Print This   Email This Email This

Passing a Class<T> for Every Type Variable T

When working on our GPCE Mint tutorial, Eddy and I realized that there is a problem when programmers use type variables inside brackets. A method like

1
2
3
4
public separable <X> Code<X> fun(Code<X> c1, Code<X> c2) {
return <| ( `(lfTest.eval(e,f).booleanCodeValue()) ?
              `c2 : `c1 )  |>;
}

causes Mint to generate code containing the free type variable X. There is no way to get any type information from a type variable at runtime, e.g. by doing X.class, so instead we decided to require the user to have a final instance of Class<X> in scope somewhere.

This was a pragmatic solution that seems to work pretty well. The method above can be rewritten as

1
2
3
4
5
public separable <X> Code<X> fun(Code<X> c1, Code<X> c2,
                                 final Class<X> xc) {
return <| ( `(lfTest.eval(e,f).booleanCodeValue()) ?
              `c2 : `c1 )  |>;
}

To implement this, we had to find all variables of type Class<X> that were in scope at the time a bracket was generated. This was surprisingly confusing to do with the javac environment and scope classes. In the end, I decided to adapt the Resolver.findVar and Resolver.findField methods.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    /** This method returns a list of all VarSymbols of type Class<X> in scope where X is a type variable. */
    List<VarSymbol> getClassVarsInScope() {
        // System.out.println("env = "+env);
        List<VarSymbol> ret = List.nil();
        Scope current = env.info.scope;
        // System.out.println("Scope: "+current);
        while(current != null) { // also go into the outer (enclosing) scopes
            // for(Symbol s: current.elems) {
            for (Scope.Entry e = current.elems; e != null; e = e.sibling) {
              ret = processPotentialClassVarInScope(e.sym, ret);
            }
            current = current.next;
        }
        // System.out.println("Asking for vars in "+env.enclClass.sym);
        ret = _getClassVarsInScope(env, ret);
        return ret.reverse();
    }
   
    List<VarSymbol> processPotentialClassVarInScope(Symbol s, List<VarSymbol> ret) {
        // System.out.println("in scope: "+s+" : "+s.getClass().getSimpleName());
        if (s instanceof VarSymbol) {
            VarSymbol vs = (VarSymbol)s;
            if ((vs.type.tsym == syms.classType.tsym) &&
                ((vs.flags() & FINAL) != 0) &&
                (vs.type.getTypeArguments().nonEmpty()) &&
                (vs.type.getTypeArguments().head instanceof TypeVar)) {
                // vs is of type Class<X> where X is a type variable
                ret = ret.prepend(vs);
            }
        }
        return ret;
    }
   
    List<VarSymbol> _getClassVarsInScope(Env<AttrContext> env, List<VarSymbol> ret) {
        Env<AttrContext> env1 = env;
        boolean staticOnly = false;
        while (env1.outer != null) {
            if (rs.isStatic(env1)) staticOnly = true;            
            Scope.Entry e = env1.info.scope.elems;
            while (e != null) {
                Symbol sym = e.sym;
                if (!(staticOnly &&
                      sym.kind == VAR &&
                      sym.owner.kind == TYP &&
                      (sym.flags() & STATIC) == 0)) {
                    ret = processPotentialClassVarInScope(sym, ret);
                }
                ret = _getClassFieldsInScope(env1, env1.enclClass.sym.type, env1.enclClass.sym, ret);
               
                e = e.sibling;
            }
            ret = _getClassFieldsInScope(env1, env1.enclClass.sym.type, env1.enclClass.sym, ret);
           
            if ((env1.enclClass.sym.flags() & STATIC) != 0) staticOnly = true;
            env1 = env1.outer;
        }

        ret = _getClassFieldsInScope(env, syms.predefClass.type, syms.predefClass, ret);
       
        return ret;
    }
   
    List<VarSymbol> _getClassFieldsInScope(Env<AttrContext> env,
                                           Type site,
                                           TypeSymbol c,
                                           List<VarSymbol> ret) {
        while (c.type.tag == TYPEVAR)
            c = c.type.getUpperBound().tsym;
        Scope.Entry e = c.members().elems;
        while (e != null) {
            if (e.sym.kind == VAR && (e.sym.flags_field & SYNTHETIC) == 0) {
                if (rs.isAccessible(env, site, e.sym)) {
                    ret = processPotentialClassVarInScope(e.sym, ret);
                }
            }
            e = e.sibling;
        }
        Type st = types.supertype(c.type);
        if (st != null && (st.tag == CLASS || st.tag == TYPEVAR)) {
            ret = _getClassFieldsInScope(env, site, st.tsym, ret);
        }
        for (Type it: types.interfaces(c.type)) {
            ret = _getClassFieldsInScope(env, site, it.tsym, ret);
        }
        return ret;
    }

A new Mint release can be expected shortly.

Posted in Mint | Leave a comment

Print This Print This   Email This Email This

New Mint Release: r15707

When working on our GPCE tutorial, Eddy and I discovered a small bug in the Mint compiler which I have now fixed in the new release of Mint and DrJava with Mint: August 24, 2010 (r15707). The latest release is, as always, available from the Mint implementation page:

The only change I made was to fix the let expression pretty printer when the expression contained more than one declaration.

The problem never came up before because we only had one declaration per let expression, and it was always possible to rewrite

1
let int x = 1, y = 2; x+y

as

1
let int x = 1; let int y = 2; x+y

We are pushing the Mint compiler more, and we have discovered another problem with generic methods. Currently, Mint generates a class extending Code<X> with X occuring unbound when this method is called:

1
public separable abstract <X> Code<X> fun(Code<X> c1, Code<X> c2, Object... param);

We are looking at making another bugfix soon.

(Re-posted from The Java Mint Blog.)

Posted in Mint | Leave a comment

Print This Print This   Email This Email This

Two Pieces of Fail

I encountered two pieces of fail today already.

Fail number 1: Absolutely no place to park my bike. This has been pretty much the case ever since the undergrads have been back. Rice built two new colleges right next to the building I work in, but didn’t consider what an increased resident population would do to bike rack space: The undergrads, of course, store their bikes semi-permanently on the bike racks that we need to commute.

This is what the bike racks looked like shortly after 9 AM this morning:

Overfull Duncan Hall Bike Rack, 9:15 AM

Overfull Duncan Hall Bike Rack, 9:15 AM

I have been lobbying for more bike racks for over a year now, to no avail. I guess I’m going to be taking my bike up into my building from now on.

Fail number 2: I still don’t have my Texas drivers license, even though it has been 67 days since I renewed it. It’s even been over three weeks since I first contacted the DPS and was told the license would be remade and resent. Today I found out why it’s taking so long:

You will be mailed out a temporary permit today while you receive your license in the mail. Apparently the license was not remade when the visitor status was updated. I sincerely apologize for the inconvenience this has caused you.


In essence, they cut up my old drivers license, updated their internal database, and never mailed me a new license. Good job, Texas DPS. I’m glad I have an international drivers license as a backup.

Posted in Pictures, Ramblings | Leave a comment

Print This Print This   Email This Email This

New Mint Release: r15700

On Friday, I created a new release of Mint and DrJava with Mint: August 20, 2010 (r15700). The latest release is, as always, available from the Mint implementation page:

The only changes that we made were a small change to the build process on Mac OS, and the addition of the Range and Lift utility classes.

The Lift class allows the user to manually lift primitive values and strings when the compiler did not do that already, for example when working with arrays.

The Range class provides methods that allow many for loops to be written as foreach loops with a final loop variable that can be used across bracket boundaries immediately. Consider this example of a staged sparse matrix multiplication:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static separable
Code<Void> smmult(final double[][] a,
                  Code<double[][]> b,
                  Code<double[][]> output,
                  int l, int m, int n) {
  Code<Void> stats = <| { } |>;
  for(final int i: range(0, l)) {
    for(final int j: range(0, m)) {
      Code<Double> c = <| 0.0 |>;
      for(final int k: range(0, n)) {
        if(a[i][k] == 0.0)
          continue;
        else if(a[i][k] == 1.0)
          c = <| `c + (`b)[k][j] |>;
        else
          c = <| `c + (`(lift(a[i][k])) * (`b)[k][j]) |>;
      }
      stats = <| { `stats; (`output)[i][j] = `c; } |>;
    }
  }
  return stats;
}

is a lot cleaner than

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static separable
Code<Void> smmult(final double[][] a,
                  Code<double[][]> b,
                  Code<double[][]> output,
                  int l, int m, int n) {
  Code<Void> stats = <| { } |>;
  for(int i = 0; i < l; i++) {
    for(int j = 0; j < m; j++) {
      final int ii = i;
      final int jj = j;
      Code<Double> c = <| 0.0 |>;
      for(int k = 0; k < n; k++) {
        final int kk = k;
        if(a[i][k] == 0.0)
          continue;
        else if(a[i][k] == 1.0)
          c = <| `c + (`b)[kk][jj] |>;
        else
          c = <| `c + (`(lift(a[ii][kk])) * (`b)[kk][jj]) |>;
      }
      stats = <| { `stats; (`output)[ii][jj] = `c; } |>;
    }
  }
  return stats;
}

The ii, jj, and kk variables aren’t necessary anymore.

(Re-posted from The Java Mint Blog.)

Posted in Mint | Leave a comment

Print This Print This   Email This Email This

Compiled “Run” Commands in DrJava

I had mentioned a while ago that the way we put together the commands that get interpreted when the user presses the “Run” button or types in java or applet or run in the Interactions Pane is very messy.

I had told myself that I should try to rewrite this as Java code that doesn’t get interpreted in our Interactions Pane, but that actually gets statically compiled. I did that, and the code was a whole lot more maintainable. Compare this code to the previous code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  /** This method performs the "smart run". Unfortunately, we don't get the right static error messages.
    * @param s full command line, i.e. "run MyClass 1 2 3"
    * @param c class to be run, i.e. MyClass.class
    */

  @SuppressWarnings("unchecked")
  public static void runCommand(String s, Class c) throws Throwable {
    if (s.endsWith(";"))  s = _deleteSemiColon(s);
    List<String> tokens = ArgumentTokenizer.tokenize(s, true);
    final String classNameWithQuotes = tokens.get(1); // this is "MyClass"
    final String className =
      classNameWithQuotes.substring(1, classNameWithQuotes.length() - 1); // removes quotes, becomes MyClass
    String[] args = new String[tokens.size() - 2];
    for (int i = 2; i < tokens.size(); i++) {
      String t = tokens.get(i);
      args[i - 2] = t.substring(1, t.length() - 1);
    }
   
    boolean isProgram = false;
    boolean isApplet = false;
    Class oldC = c;
    while(c != null) {
      if ("acm.program.Program".equals(c.getName()) ||
          "acm.graphics.GTurtle".equals(c.getName())) { isProgram = true; break; }
      c = c.getSuperclass();
    }
    c = oldC;
    if (!isProgram) {
      try {
        // if this doesn't throw, c is a subclass of Applet
        c.asSubclass(java.applet.Applet.class);
        isApplet = true;
      } catch(ClassCastException cce) { }
    }

    java.lang.reflect.Method m = null;
    if (isApplet) {
      try {
        m = c.getMethod("main", java.lang.String[].class);
        if (!m.getReturnType().equals(void.class)) { m = null; }
      }
      catch (java.lang.NoSuchMethodException e) { m = null; }
      if (m==null) {
        java.applet.Applet instance = null;
        if (args.length==0) {
          try {
            // try default (nullary) constructor first
            Constructor ctor = c.getConstructor();
            instance = java.applet.Applet.class.cast(ctor.newInstance());
          }
          catch(NoSuchMethodException nsme) { instance = null; }
          catch(InstantiationException ie) { instance = null; }
          catch(IllegalAccessException iae) { instance = null; }
          catch(java.lang.reflect.InvocationTargetException ite) {
            if (ite.getCause()!=null) {
              throw ite.getCause();
            }
            else {
              System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
            }
          }
          if (instance==null) {
            try {
              // try String[] constructor next
              Constructor ctor = c.getConstructor(String[].class);
              instance = java.applet.Applet.class.cast(ctor.newInstance(new Object[] { new String[0] }));
            }
            catch(NoSuchMethodException nsme) { instance = null; }
            catch(InstantiationException ie) { instance = null; }
            catch(IllegalAccessException iae) { instance = null; }
            catch(java.lang.reflect.InvocationTargetException ite) {
              if (ite.getCause()!=null) {
                throw ite.getCause();
              }
              else {
                System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
                return;
              }
            }
          }
          if (instance==null) {
            System.err.println("Error: This applet does not have a default constructor or a constructor "+
                               "accepting String[].");
            return;
          }
        }
        else {
          try {
            // try String[] constructor
            Constructor ctor = c.getConstructor(String[].class);
            instance = java.applet.Applet.class.cast(ctor.newInstance(new Object[] { args }));
          }
          catch(NoSuchMethodException nsme) { instance = null; }
          catch(InstantiationException ie) { instance = null; }
          catch(IllegalAccessException iae) { instance = null; }
          catch(java.lang.reflect.InvocationTargetException ite) {
            if (ite.getCause()!=null) {
              throw ite.getCause();
            }
            else {
              System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
              return;
            }
          }
          if (instance==null) {
            System.err.println("Error: This applet does not have a constructor accepting String[].");
            return;
          }
        }
        edu.rice.cs.plt.swing.SwingUtil.showApplet(instance, 400, 300);
      }
    }
    else {
      try {
        m = c.getMethod("main", java.lang.String[].class);
        if (!m.getReturnType().equals(void.class)) {
          System.err.println("Error: This class does not have a static void main method accepting String[].");
          m = null;
        }
      }
      catch (java.lang.NoSuchMethodException e) {
        System.err.println("Error: This class does not have a static void main method accepting String[].");
        m = null;
      }
    }
    if (m != null) {
      if (isProgram) {
        String[] newArgs = new String[args.length+1];
        newArgs[0] = "code="+c.getName();
        System.arraycopy(args, 0, newArgs, 1, args.length);
        args = newArgs;
      }
      try {
        m.setAccessible(true);
        m.invoke(null, new Object[] { args });
      }
      catch(SecurityException se) {
        System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
      }
      catch(IllegalAccessException iae) {
        System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
      }
      catch(java.lang.reflect.InvocationTargetException ite) {
        if (ite.getCause()!=null) {
          throw ite.getCause();
        }
        else {
          System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
        }
      }
    }
  }

It’s actual Java code that is statically compiled, not a string that is concatenated at runtime and that might be erroneous.

Unfortunately, we don’t get the right static error messages. I can print something like “Static Error: Undefined class ‘Foo’” as output, but it doesn’t have the right font and doesn’t invoke the right listeners, so the “Auto-Import” dialog doesn’t show up, for example.

For now, I’m using the old string concatenation routine again.

Posted in DrJava | Leave a comment

Print This Print This   Email This Email This

Java Versions on the Mac

Stephen had some questions about Java on the Mac. I tried to answer them.

From the DrJava site, I see notes that a JDK is already installed on OS X machines—that explains why I can’t find downloads for it.


There are some Java downloads from Apple, but they’re hard to find and meant for developers (Apple ID required).

I have a couple of questions about it though:


Here are some answers from Apple: Mac OS X Java Frequently Asked Questions (FAQ) for developers.

a) Is it a 32-bit or a 64-bit JDK?


As far as I know, Macs have both a 32-bit and a 64-bit JDK installed. If I understand this page correctly, by default, the 32-bit JVM is running.

I don’t have a 64-bit Mac, though, so I don’t have any experience with 64-bit Mac JVMs.

b) Does the Mac run some sort of auto-updating process on it – how do you know what version it is running and how do you get a newer version if needed?


This is what the FAQ says:

Java updates usually stand alone, allowing you to choose when an update is appropriate. However, it is always recommended to check the description and release notes for all software updates to see which technologies are affected. Major upgrades such as Mac OS X Leopard typically update Java as well.


It’s been such a long time since I’ve had a Java update on my 10.4 32-bit MacBook, but I think new versions of Java appear in the “Software Update” list (see Apple menu).

The reason I ask is that for running Eclipse, one needs to know if you’re running a 32-bit or 64-bit version because not only are different plug-ins needed, but the install procedure can be different as well. Also, we need to know what version of Java people are running on their Macs.


On the command line: java -version

The sun.arch.data.model property may also help, it should be "32", "64" or "unknown". You can get the value by calling System.getProperty("sun.arch.data.model"), for example in the DrJava Interactions Pane (see Oracle FAQ entry).

Here is some more Apple-specific information about Java versions.

Hope this helps.

Update

Corky said what I had written about “by default, the 32-bit JVM is running” had confused him. He wondered: “Is a 32 bit version of Java 6 now available on Leopard?”

No, there’s still no 32-bit Java 6 from Apple for Tiger (10.4).

It seems like the -d64 switch is a mode, like -server or -client, and that on the Mac both the 32-bit and the 64-bit JVMs are rolled into one. On Windows, Linux and Solaris, there are 32-bit and 64-bit JVMs that need to be installed separately.

Posted in Uncategorized | Leave a comment

Print This Print This   Email This Email This

GPCE’10 Tutorial Lecture: Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint

Eddy and I proposed a tutorial lecture for GPCE’10, and we’re delighted to report that it has been accepted for presentation on Sunday, October 10, 2010.

Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint

Domain-specific languages (DSLs) are a powerful productivity tool because they allow domain experts, who are not necessarily programming experts, to quickly develop programs. DSL implementations have unique constraints for programming languages because they must be efficient, in order to ensure high productivity, but they must also be agile, in order to meet the rapidly changing demands of their domains. In this tutorial we show how multi-stage programming (MSP) can be used to build staged interpreters, which combine the agility of interpreters with the efficiency of compilers. The tutorial is conducted in Java Mint, an multi-stage Java based on recent work incorporating MSP into imperative object-oriented languages. In the first half of the tutorial, we introduce MSP by demonstrating how to write a staged interpreter for a number of basic language constructs, such as recursive functions, conditionals, and let expressions. In the second half, we extend our staged interpreter to take advantage of several well-known compiler optimizations, including type inference, constant folding, and static parallel loop scheduling. We highlight the opportunities afforded by using MSP with object-oriented design to quickly create efficient DSL implementations.


Brief Outline of Tutorial

This tutorial uses Java Mint to introduce MSP in imperative, object-oriented languages. We will progress as follows:

  1. Introduction to MSP, the three language constructs “bracket”, “escape” and “run”, and their use in Java Mint.
  2. Brief overview of MSP applications other than interpreters.
  3. Development of a staged interpreter for a small DSL. We incrementally add:
    1. Arithmetic expressions
    2. Conditionals
    3. Recursive functions
    4. Let expressions
  4. Application of compiler optimizations in the interpreter for our DSL. We discuss:
    1. Extending the interpreter with multiple data types
    2. Type inference
    3. Constant folding
    4. Static parallel loop scheduling


Biographies

Mathias Ricken is a doctoral candidate in the Programming Languages Team at Rice University and one of the principal developers of the DrJava integrated development environment. His research interests include concurrent programming, extending the Java language, and computer science education. He is the developer of the Concutest concurrent unit testing framework and has created various experimental extensions of Java to address, for instance, programming with meta-data. Currently, Mathias is contributing to Java Mint, a multi-stage extension of Java that allows safe and expressive statically typed program generation and specialization in an imperative language setting.

Edwin Westbrook is a post-doctoral researcher at Rice University. His primary interests are in developing techniques for implementing and verifying properties of domain-specific languages (DSLs). He has worked on a number of projects in this area, including: Cinic, a type theory for building machine-checked proofs of properties of DSLs using a new approach to higher-order abstract syntax; Java Mint, a multi-stage version of Java used for efficient implementations of DSLs; and Acumen, a DSL for designing cyber-physical systems.

(Re-posted from The Java Mint Blog.)

Posted in Mint | 2 Comments

Print This Print This   Email This Email This

New Version of DrJava with Mint: drjava-r5366-mint-r15665

The DrJava team released a new stable version of DrJava today, drjava-stable-20100816-r5366.

I therefore created a new release of DrJava with Mint: August 16, 2010 (drjava-r5366-mint-r15665.jar). The latest release is available from the Mint implementation page:

Nothing has changed on the Mint language side.

(Re-posted from The Java Mint Blog.)

Posted in DrJava, Mint | Leave a comment

Print This Print This   Email This Email This

New DrJava Stable Release: drjava-stable-20100816-r5366

We have just released a new stable release of DrJava: drjava-stable-20100816-r5366. You can download it from SourceForge or from the DrJava homepage.

Available for download at http://drjava.org .

DrJava is a lightweight programming environment for Java designed to foster test-driven software development. It includes an intelligent program editor, an interactions pane for evaluating program text, a source level debugger, and a unit testing tool.

In addition to bug fixes, this stable release includes a number of new features introduced after the last beta release:

These features include improved keyboard shortcuts, improved undo/redo functionality outside the Definitions Pane, as well as better menus for detached windows on the Mac.

Note: Java 1.4 compatibility has been dropped. To use DrJava, you will need Java 5 or newer.

New features since the last beta release:

  • Keyboard shortcuts for Project menu items.
  • Menus for detached windows on Mac OS.
  • Undo/Redo for Input Box and detached Interactions Pane.
  • Keyboard shortcuts available in detached windows.
  • Displaying compiz warning only for Java older than 1.6.0_20.
  • Changing the default look-and-feel for non-Windows, non-Mac machines (=Linux) to the system default. This will probably be GTK instead of Metal, which is much prettier.

Bug fixes since last beta release:

  • Properly disabled ‘Run Project’s Main Class’ if main class not set.
  • Bugfix for a problem relating to menu item availability, which caused the project menu to be disabled when it should be enabled.
  • IllegalAccessException with Smart Run on non-Public class.
  • Fixed NullPointerException when removing Find All matches.
  • Fixed a bug that caused a NullPointerException when a Find All encountered a missing file.
  • Fixed bug StringIndexOutOfBoundsException on non-Western systems that use characters longer than a byte.
  • Fixed bug that caused Undo/Redo menu items to not be enabled properly.
  • Fixed bug that caused pressing Ctrl-Z (Undo) to make the System.in box disappear.
  • Fixed bug that caused { or } to be inserted on Linux when using “Go to Opening/Closing Brace” shortcuts.
  • Fixed a bug that enabled Undo for the Interactions Pane on Macs even when there was nothing to undo.
  • Fixed problem that prevented configuration of key bindings for actions with the same names, e.g. “New” (File) and “New” (Project).
  • Fixed bug that caused changes to Key Bindings to not be canceled properly.

New features since the last stable release:

  • The Eclipse Java Compiler is now integrated into DrJava. DrJava therefore does not require the JDK anymore to compile programs. Note that the JDK is still required to use the debugger or to create Javadoc.
  • DrJava supports the OpenJDK and JavaMint (multi-stage programming in Java; see http://www.javamint.org/ ) compilers.
  • JUnit 4.7 support.
  • ConcJUnit support (for concurrent unit tests; see http://www.concutest.org/ ).
  • Access control for private and package private members now enabled by default.
  • DynamicJava (Interpreter) error messages are much better, especially those involving method and constructor invocation.
  • Added support in DynamicJava for explicit type arguments in local function invocations (x = foo(23)).
  • The Breakpoint, Bookmarks, and Find Results tabbed panes now have Previous/Next buttons and associated keyboard shortcuts for simpler browsing.
  • The Interactions Pane working directory can now be specified even when not using projects.
  • If DrJava cannot start, for example because of bad memory settings in the Preferences, DrJava will suggest that you let it reset the Preferences.
  • The preferred compiler can now be set, and this setting will be restored when DrJava starts the next time.
  • Zoom for Print Preview.
  • New Class wizard.
  • Save Copy ability for Definitions documents, Interactions Pane and Console Pane contents.
  • The Java Language Level facility has been simplified. There now is only one language level called “Functional Java”, using the file extension .dj. It is comparable to the Intermediate level and can still compile .dj0 and .dj1 files. .dj2 files are compiled using the Full Java compiler. DrJava will suggest that you rename .dj0 and .dj1 files to .dj files, and .dj2 files to .java files.
  • DrJava can generate a custom .jar file of itself that includes additional files. There is a Tools/Advanced/Generate Custom drjava.jar menu item that takes the current DrJava executable file and a number of user-specified files to generate a new jar file.
    • The libraries included in the new jar file will then automatically be included in the classpath and be usable without adding them to a classpath somewhere.
    • There is no functionality to remove the libraries again from the modified jar file.
    • Generating a custom DrJava jar file disables the check for updated versions. Otherwise a user may download an updated version that doesnt have required libraries anymore.
  • When DrJava encounters missing files during a “Find All” search, it will ask the user whether to continue or abort the search.
  • Improved “New Java Class” dialog with some auto-completion.
  • Better feedback when Java API data is loaded, which may involve some delay if it is retrieved from the internet.
  • There is a new option in Preferences/Interactions Pane called “Smart Run (‘java’) Command”. If enabled (default), the “Run” button and the “java” command in the Interactions Pane detects if the class (a) is an ACM Java Task Force program (subclass of acm.program.Program) or (b) an applet. If (a), then it runs the program’s main method, but inserts “code=MyClass” as argument 0. If (b), it starts the applet viewer. Otherwise, the “java” command behaves just as before.
  • Right margin line.
  • Improved Save As file naming.
  • Tools->Advanced->New DrJava Instance feature.
  • Appending .jar to file name when generating custom DrJava.

Bug fixes since the last stable release:

  • Fixed some indentation bugs.
  • Fixed some GUI initialization problems that prevented DrJava from starting on some systems.
  • Fixed a bug that prevented DrJava from opening on MacOS 10.5 or 10.6.
  • Fixed compiler error when closing curly brace missing.
  • Fixed NullPointerException in Jar Project dialog.
  • Fixed a bug that prevented users from editing External Processes.
  • Fixed a bug in un-commenting source code.
  • Fixed a bug in displaying the Auto-Import dialog in the Interactions Pane.
  • Improved suggestion to increase interactions JVM heap.
  • Improved responsiveness when selecting a compiler.
  • Fixed a bug that prevented users from generating Javadoc of Language Level files.
  • DynamicJava (Interpreter) bug fix allows the declaration of interfaces.
  • Miscellaneous small DynamicJava bug fixes make it much more robust and correct, including better handling of member lookup, inner classes, enums, interfaces, raw types, static imports, switch statements, casts, and final variables.
  • Bugfix for comparing 0.0 == -0.0 and NaNs.
  • Bugfix in DynamicJava: Supports annotation declarations
  • Bugfix in DynamicJava: Fixes parser bug for enums
  • Bugfix in DynamicJava: Fixes implicit accessibility of interface members
  • Bugfix in DynamicJava: Fixes checking of assignments from character literals
  • Bugfix in DynamicJava: Improves checking of casts
  • Bugfix in DynamicJava: getClass() is a special method with type Class for all classes
  • Bugfix in DynamicJava: Improves error messages for inner class references
  • Bugfix in DynamicJava: Preserves location in wildcards
  • Bugfix in DynamicJava: Catches errors that occur during static initialization of a class
  • Bugfix in DynamicJava: Short-circuiting during type checking
  • Bugfix in DynamicJava: += for strings
  • Bugfix in DynamicJava: Array initializer is assigned to a non-array type
  • Misc improvements to DynamicJava SoureChecker
  • Bugfix that prevented users from watching local variables in the Debugger.
  • Smaller Java Language Level fixes.
  • StringIndexOutOfBoundsException During Next Word
  • Exception when double click on External process tab
  • This commit fixes some glitches in the new functional LL, effectively subsuming both the Elementary (.dj0) and Intermediate (.dj1) language levels.
  • Bugfix for throw null
  • Fixing a memory leak in DefinitionsPane.
Posted in DrJava | Leave a comment

Print This Print This   Email This Email This

Improved DrC#?

Recently, I was asked if there will ever be a new DrC# which is similar to DrJava.

Unfortunately, I don’t expect an improved DrC# in the near future. We don’t have the funding and personnel to work on such a project. We already have trouble maintaining the DrJava Plug-in for Eclipse.

It may be possible to integrate a C# command line compiler into DrJava, though, if there is interest. There are problems with this approach, though: The syntax highlighting wouldn’t be right, and the Interactions Pane wouldn’t be functional.

Posted in DrJava | Leave a comment

Print This Print This   Email This Email This

I’m Going to Eindhoven

The Java Mint tutorial lecture called “Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint“, which Eddy and I proposed, has been accepted at GPCE 2010.

I’m looking forward to being in Eindhoven in October. Before that, on September 20, Eddy and I will have an opportunity to practice the lecture in our COMP 600 Graduate Research Seminar.

Posted in Mint | Leave a comment

Print This Print This   Email This Email This

Tutorial Lecture: Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint

Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint (PDF, view embedded)

Mathias Ricken and Edwin Westbrook

A tutorial lecture to be presented at the

Ninth International Conference on Generative Programming and Component Engineering (GPCE’10)

October 10-13, 2010
Eindhoven, The Netherlands

Abstract

Domain-specific languages (DSLs) are a powerful productivity tool because they allow domain experts, who are not necessarily programming experts, to quickly develop programs. DSL implementations have unique constraints for programming languages because they must be efficient, in order to ensure high productivity, but they must also be agile, in order to meet the rapidly changing demands of their domains. In this tutorial we show how multi-stage programming (MSP) can be used to build staged interpreters, which combine the agility of interpreters with the efficiency of compilers. The tutorial is conducted in Java Mint, an multi-stage Java based on recent work incorporating MSP into imperative object-oriented languages. In the first half of the tutorial, we introduce MSP by demonstrating how to write a staged interpreter for a number of basic language constructs, such as recursive functions, conditionals, and let expressions. In the second half, we extend our staged interpreter to take advantage of several well-known compiler optimizations, including type inference, constant folding, and static parallel loop scheduling. We highlight the opportunities afforded by using MSP with object-oriented design to quickly create efficient DSL implementations.

Author Biographies

Mathias Ricken is a doctoral candidate in the Programming Languages Team at Rice University and one of the principal developers of the DrJava integrated development environment. His research interests include concurrent programming, extending the Java language, and computer science education. He is the developer of the Concutest concurrent unit testing framework and has created various experimental extensions of Java to address, for instance, programming with meta-data. Currently, Mathias is contributing to Java Mint, a multi-stage extension of Java that allows safe and expressive statically typed program generation and specialization in an imperative language setting.

Edwin Westbrook is a post-doctoral researcher at Rice University. His primary interests are in developing techniques for implementing and verifying properties of domain-specific languages (DSLs). He has worked on a number of projects in this area, including: Cinic, a type theory for building machine-checked proofs of properties of DSLs using a new approach to higher-order abstract syntax; Java Mint, a multi-stage version of Java used for efficient implementations of DSLs; and Acumen, a DSL for designing cyber-physical systems.

Posted in Publications | 1 Comment

Print This Print This   Email This Email This

drjava.org Temporarily Unavailable

Our DrJava website is currently not available under the usual address (http://drjava.org). We are working on fixing this problem as quickly as possible.

If you need access to the DrJava website in the meantime, please use one of these two URLs instead:

http://drjava.sourceforge.net/ http://www.cs.rice.edu/~javaplt/drjava/

We apologize for the inconvenience. Thanks for using DrJava!

Update

At some point during the morning of August 15, the domain started working again. We are happy to report that our website is available again under the usual address: http://drjava.org .

Posted in DrJava | Leave a comment

Print This Print This   Email This Email This

Rice University Virtual Tour

These are really cool panorama pictures of my university:

Experience Rice University’s 300-acre campus and its urban surroundings by taking our virtual tour http://bit.ly/a7Yt0I


If you click on the fourth image from the left in the navigation bar at the bottom, you can see my office building, Duncan Hall.

Duncan Hall at Rice University

Duncan Hall at Rice University

Posted in Uncategorized | Leave a comment

Print This Print This   Email This Email This