[Prev][Next][Index][Thread]

Re: ICFP - OCaml entry



In article <8op70f$n3e$1@rznews2.rrze.uni-erlangen.de>, "Gabor Greif" 
<gabor@mac.com> wrote:

> All syntactic and semantic errors are caught by the use of type 
> contraints and are reported by a top-level handler.

I thought this was especially cool.

Semantic errors are pretty strightforward.  For example, the rutime code 
for binary operators is the closure:

method(stack :: <pair>, env :: <function>) => new-stack :: <list>;
  let (right :: ?back, rest :: <pair>) = values(stack.head, stack.tail);
  let (left :: ?front, rest :: <list>) = values(rest.head, rest.tail);
  cont(pair(?operator(left, right), rest), env)
end method,

After macro-expansion ?operator will be e.g. * or + and ?front and ?back 
will be Dylan types such as <integer> or <double-float> or <boolean>.  
If the stack turns out to be empty, or contains the wrong sorts of 
values then the attempt to assign them to "right" and "left" will cause 
a language exception, which we catch elsewhere.  

The type declarations serve the dual purpose of dynamically making sure 
that we have the right sort of operands, and then the compiler can 
statically determine which method on "+" we need ... int + int, or float 
+ float.  Having no explicit error handling code is pretty cool, I think!


Syntax errors are interesting.  There really aren't many in GML.  An 
unmatched ] or } is about the only one:

define method compile-one(token == '{', more-tokens :: <pair>)
 => (closure :: <function>, remaining :: <list>);

  let (closure, remaining) = more-tokens.optimize-compile-GML;
  let (closing :: '}'.singleton, remaining :: <list>)
    = values(remaining.head, remaining.tail);
  let (cont, remaining) = remaining.optimize-compile-GML;
  values(method(stack :: <list>, env :: <function>)
          => new-stack :: <list>;
           cont(pair(rcurry(closure, env), stack), env)
         end,
         remaining)
end;

The interesting part here is that the syntax checking is done by parsing 
everything you can from the body of the function 
("more-tokens.optimize-compile-GM") and then simply assigning the next 
token to a variable ("closing") which is declared with a type that has 
only a single value.  We can ignore the actual contents of "closing" 
(and the compiler doesn't even have to allocate space for it!) because 
if we get past the typecheck without throwing an exception then we 
already know that closing = '}'.

-- Bruce



References: