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

Re: [Scheme-reports] library at file level



On 05/13/2013 07:19 AM, John Cowan wrote:
> Sam TH scripsit:
>
>> This is simply incoherent. If macros can be defined by procedures,
>> then mutually recursive libraries each of which export macros cannot
>> be sensibly expanded.  What does your system do in this case?
>
> It actually isn't incoherent, provided the recursion is indirect and the
> compiler can process both libraries simultaneously.  Thus suppose that
> library (a) defines procedures aproc and aaux and macro amac, and library
> (b) defines procedures bproc and baux and macro bmac.  It is perfectly
> intelligible for aproc to be defined using bmac, which is defined using
> baux, and bproc to be defined using amac, which is defined using aaux.
> The two libraries must import each other, which is banned by R6RS;
> what is more, probably most compilers can't handle this because they
> only compile one library at a time.

More specifically, the Kawa compiler is organized in multiple phases.
This is like most compilers, but what is less usual is that the
phases are interleaved for different libraries.

When module A imports module B, Kawa will attempt to load B.class
(if it has been previously compiled and is up-to-date).  If that
doesn't work it will compile B, starting with the read+scan phase.
If there are no cycles if will completely compile B, and load it,
so it can run syntax transformers in B used by A.  If there is a
cycle, then Kawa will note the dependency and defer remaining
phases.  Then each phases is done in order: Before running phase N
on module A, Kawa will run phase N-1 on all libraries that A
depends on.

On 05/13/2013 06:12 AM, Sam TH wrote
> As to phasing, phasing is a solution to a problem. Not worrying about
> it does not obviate the need to solve the problem.  Even Common Lisp
> provides `eval-when` and similar for addressing these issues.  What
> does Kawa do?

When it comes to phasing, yes it is definitely an issue, but it
isn't specific to libraries.  Kawa's phasing is somewhat implicit.
It uses an interpreter if it needs to evaluate a syntax transformer
before it is fully compiled.  This isn't as elegant as one would like,
but it seems to work well in practice.

I did a little experiment to see what would happen with a bad
phasing dependency (not a cycle):

(define (id x) x)
(define-syntax tr
   (lambda (form)
     (syntax-case form ()
       ((_ exp)
        (id #'exp)))))
(tr (newline))

Compiling this results in:

$ kawa -C   /tmp/foo.scm
(compiling /tmp/foo.scm)
/tmp/foo.scm:7:1: evaluating syntax transformer 'tr' threw 
/tmp/foo.scm:6:8: unbound location id

Not as good an error message as one would like, but acceptable, I think.

Evaluating it in "whole-module" mode (i.e. read and compile entire file
before evaluation) has the same result:

$ kawa   /tmp/foo.scm
/tmp/foo.scm:7:1: evaluating syntax transformer 'tr' threw 
/tmp/foo.scm:6:8: unbound location id

Evaluating it in line-by-line mode works:

$ kawa -f /tmp/foo.scm

$

Kawa does have define-for-syntax, which wraps a define in a 
begin-for-syntax,
which calls eval (at compile-time) on the form.  Admittedly a kludge:

(define-syntax begin-for-syntax
   (lambda (form)
     (syntax-case form ()
       ((begin-for-syntax . body)
        (eval (syntax-object->datum (gnu.lists.Pair 'begin (syntax body))))
        (syntax #!void)))))

(define-syntax define-for-syntax
   (syntax-rules ()
     ((define-for-syntax . rest)
      (begin-for-syntax
       (define . rest)))))

These are only used in a couple of testcases, so they're probably
not very robust ...
-- 
	--Per Bothner
per@x   http://per.bothner.com/

_______________________________________________
Scheme-reports mailing list
Scheme-reports@x
http://lists.scheme-reports.org/cgi-bin/mailman/listinfo/scheme-reports