[Top][All Lists]

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

an end to oppression

From: Andy Wingo
Subject: an end to oppression
Date: Fri, 14 Nov 2008 23:29:27 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.60 (gnu/linux)


Are you feeling oppressed because the misguided authors of Guile's
compiler did not see fit to include your crucially important
optimization pass, or did not add support for the passes needed in your
language? I though so. I can feel these things. Well suffer no more,
because Guile now has a fully generic compiler infrastructure.

What? You don't know what an FGCI is? Clearly you are not as up on the
literature as you pretend to be. Allow me to paste some code from the
newly shortened (system base compile):

    (define *current-language* (make-fluid))
    (define (current-language)
      (or (fluid-ref *current-language*)
          (begin (fluid-set! *current-language* (lookup-language 'scheme))

Here we define some bits to set the current language, which defaults to

    (define (compile-passes from to opts)
      (let lp ((langs (or (lookup-compilation-order from to)
                          (error "no way to compile" (language-name from)
                                 "to" (language-name to))))
               (out '()))
        (if (null? (cdr langs))
            (reverse! out)
            (lp (cdr langs)
                (cons (assq-ref (language-compilers (car langs)) (cadr langs))

This function computes the ordered list of functions to fold over the
source expression and environment. It's language-neutral.

    (define (compile-fold passes exp env opts)
      (if (null? passes)
          (receive (exp env) ((car passes) exp env opts)
            (compile-fold (cdr passes) exp env opts))))

    (define* (compile x #:key
                      (env #f)
                      (from (current-language))
                      (to value)
                      (opts '()))
      (compile-fold (compile-passes from to opts)

As are these functions. The latter is the primary runtime compilation
interface, `compile-file' being the other one. Here's the bits about
looking up compilation passes, from (system base language):

    (define (compute-compilation-order from to)
      (let lp ((from from) (seen '()))
        (cond ((eq? from to) (reverse! (cons from seen)))
              ((memq from seen) #f)
              (else (or-map (lambda (lang) (lp lang (cons from seen)))
                            (map car (language-compilers from)))))))

    (define (lookup-compilation-order from to)
      (or (assoc-ref *compilation-cache* (cons from to))
          (let ((order (compute-compilation-order from to)))
            (set! *compilation-cache*
                  (acons (cons from to) order *compilation-cache*))

And to round out this exposition, here's the definition of the GHIL

    (define-language ghil
      #:title       "Guile High Intermediate Language (GHIL)"
      #:version     "0.3"
      #:reader      read
      #:printer     write-ghil
      #:parser      parse
      #:compilers   `((,glil . ,compile-il)))

The default target language is "value", which is a bit of a hack -- we
want to compile to objcode (a language), then turn that objcode into a
thunk and run the thunk. The latter operations are modeled as
translating a language of a static array of bytes (objcode) into Scheme
values -- thus a "compiler" from objcode to value.

Now that I think of it, there's a quine lurking here:

  ((lambda (x) ((compile x) x)) '(lambda (x) ((compile x) x)))

I feel like there's some further simplicity here, though perhaps not.
(Note that compile is equivalent to eval in this case.)

Happy hacking,


reply via email to

[Prev in Thread] Current Thread [Next in Thread]