[Prev][Next][Index][Thread]
Re: ICFP - OCaml entry
-
To: info-dylan@ai.mit.edu
-
Subject: Re: ICFP - OCaml entry
-
From: Bruce Hoult <bruce@hoult.org>
-
Date: Fri, 1 Sep 2000 19:30:01 -0400 (EDT)
-
Organization: The Internet Group Ltd
-
References: <8omb1a$p7j$1@bird.wu-wien.ac.at> <bruce-48F69F.08412001092000@news.akl.ihug.co.nz> <8omtsv$u1o$1@bird.wu-wien.ac.at> <bruce-B1CB8E.13334701092000@news.akl.ihug.co.nz> <Pine.BSF.4.21.0009010814230.24436-100000@shell5.ba.best.com> <8op70f$n3e$1@rznews2.rrze.uni-erlangen.de>
-
User-Agent: MT-NewsWatcher/3.0 (PPC)
-
Xref: traf.lcs.mit.edu comp.lang.functional:20850 comp.lang.dylan:12675
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: