;;; Guile High Intermediate Language ;; Copyright (C) 2001 Free Software Foundation, Inc. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Code: (define-module (system il ghil) :use-module (oop goops) :use-syntax (system base syntax) :use-module (ice-9 match) :use-module (ice-9 regex) :export (parse-ghil ghil-lookup ghil-primitive? make- ? -1 -2 make- ? -1 -2 -3 make- ? -1 -2 -3 make- ? -1 -2 -3 make- ? -1 -2 -3 make- ? -1 -2 -3 make- ? -1 -2 -3 -4 make- ? -1 -2 -3 -4 make- ? -1 -2 -3 -4 -5 make- ? -1 -2 -3 make- ? -1 -2 -3 make- ? -1 -2 -3 make- ? -1 -2 -3 -4 -5 make- ? -1 -2 -3 -4 -5 make- ? -1 -2 -3 -4 make- ? -1 -2 -3 -4 )) ;;; ;;; Parse tree ;;; (define-structure ( env loc)) (define-structure ( env loc obj)) (define-structure ( env loc exp)) (define-structure ( env loc exp)) (define-structure ( env loc exp)) (define-structure ( env loc var)) (define-structure ( env loc var val)) (define-structure ( env loc var val)) (define-structure ( env loc test then else)) (define-structure ( env loc exps)) (define-structure ( env loc exps)) (define-structure ( env loc exps)) (define-structure ( env loc vars vals body)) (define-structure ( env loc vars rest body)) (define-structure ( env loc proc args)) (define-structure ( env loc inline args)) (define-public (ghil-env ghil) (vector-ref ghil 1)) (define-public (ghil-loc ghil) (vector-ref ghil 2)) ;;; ;;; Procedures ;;; (define *core-primitives* '(@void @quote @define @set! @if @begin @let @letrec @lambda)) (define *macro-module* (resolve-module '(system il macros))) (define (ghil-primitive-macro? x) (and (module-defined? *macro-module* x) (procedure? (module-ref *macro-module* x)))) (define (ghil-macro-expander x) (module-ref *macro-module* x)) (define (ghil-primitive? x) (or (memq x *core-primitives*) (ghil-primitive-macro? x))) ;;; ;;; Variables ;;; (define-vm-class () env name kind type value index) (define-public (make-ghil-var env name kind) (make :env env :name name :kind kind)) (define-method (write (var ) port) (display "#" port)) ;;; ;;; Modules ;;; (define-vm-class () (module) (table '()) (imports '())) (define-public (make-ghil-mod module) (make :module module)) (define-method (write (mod ) port) (display "#" port)) (define-method (ghil-lookup (mod ) (sym )) (or (assq-ref mod.table sym) ;; (let ((var (make-ghil-var (env-identifier mod.module) sym 'module))) (let ((var (make-ghil-var #f sym 'module))) (set! mod.table (acons sym var mod.table)) var))) ;;; ;;; Environments ;;; (define-vm-class () (mod) (parent #f) (table '()) (variables '())) (export make-ghil-env) (define-method (make-ghil-env (m )) (make :mod m :parent m)) (define-method (make-ghil-env (e )) (make :mod e.mod :parent e)) (define (ghil-env-toplevel? e) (eq? e.mod e.parent)) (define-method (ghil-env-ref (env ) (sym )) (assq-ref env.table sym)) (export ghil-env-add!) (define-method (ghil-env-add! (env ) (var )) (set! env.table (acons var.name var env.table)) (set! env.variables (cons var env.variables))) (define-method (ghil-env-remove! (env ) (var )) (set! env.table (assq-remove! env.table var.name))) (define-method (ghil-lookup (env ) (sym )) (or (ghil-env-ref env sym) (let loop ((e env.parent)) (cond ((is-a? e ) (ghil-lookup e sym)) ((ghil-env-ref e sym) => (lambda (var) (set! var.kind 'external) var)) (else (loop e.parent)))))) (define-public (call-with-ghil-environment e syms func) (let* ((e (make-ghil-env e)) (vars (map (lambda (s) (let ((v (make-ghil-var e s 'argument))) (ghil-env-add! e v) v)) syms))) (func e vars))) (define-public (call-with-ghil-bindings e syms func) (let* ((vars (map (lambda (s) (let ((v (make-ghil-var e s 'local))) (ghil-env-add! e v) v)) syms)) (ret (func vars))) (for-each (lambda (v) (ghil-env-remove! e v)) vars) ret)) ;;; ;;; Parser ;;; (define (parse-ghil x e) (parse `(@lambda () ,x) (make-ghil-mod e))) (define (parse x e) (cond ((pair? x) (parse-pair x e)) ((symbol? x) (let ((str (symbol->string x))) (case (string-ref str 0) ((#\@) (error "Invalid use of IL primitive" x)) ((#\:) (let ((sym (string->symbol (substring str 1)))) (make- (symbol->keyword sym)))) (else (make- e (ghil-lookup e x)))))) (else (make- x)))) (define (map-parse x e) (map (lambda (x) (parse x e)) x)) (define (parse-pair x e) (let ((head (car x)) (tail (cdr x))) (if (and (symbol? head) (eq? (string-ref (symbol->string head) 0) #\@)) (if (ghil-primitive-macro? head) (parse (apply (ghil-macro-expander head) tail) e) (parse-primitive head tail e)) (make- e (parse head e) (map-parse tail e))))) (define (parse-primitive prim args e) (case prim ;; (@ IDENTIFIER) ((@) (match args (() (make- e (make-ghil-var '@ '@ 'module))) ((identifier) (receive (module name) (identifier-split identifier) (make- e (make-ghil-var module name 'module)))))) ;; (@@ OP ARGS...) ((@@) (match args ((op . args) (make- op (map-parse args e))))) ;; (@void) ((@void) (match args (() (make-)))) ;; (@quote OBJ) ((@quote) (match args ((obj) (make- obj)))) ;; (@define NAME VAL) ((@define) (match args ((name val) (let ((v (ghil-lookup e name))) (make- e v (parse val e)))))) ;; (@set! NAME VAL) ((@set!) (match args ((name val) (let ((v (ghil-lookup e name))) (make- e v (parse val e)))))) ;; (@if TEST THEN [ELSE]) ((@if) (match args ((test then) (make- (parse test e) (parse then e) (make-))) ((test then else) (make- (parse test e) (parse then e) (parse else e))))) ;; (@begin BODY...) ((@begin) (parse-body args e)) ;; (@let ((SYM INIT)...) BODY...) ((@let) (match args ((((sym init) ...) body ...) (let* ((vals (map-parse init e)) (vars (map (lambda (s) (let ((v (make-ghil-var e s 'local))) (ghil-env-add! e v) v)) sym)) (body (parse-body body e))) (for-each (lambda (v) (ghil-env-remove! e v)) vars) (make- e vars vals body))))) ;; (@letrec ((SYM INIT)...) BODY...) ((@letrec) (match args ((((sym init) ...) body ...) (let* ((vars (map (lambda (s) (let ((v (make-ghil-var e s 'local))) (ghil-env-add! e v) v)) sym)) (vals (map-parse init e)) (body (parse-body body e))) (for-each (lambda (v) (ghil-env-remove! e v)) vars) (make- e vars vals body))))) ;; (@lambda FORMALS BODY...) ((@lambda) (match args ((formals . body) (receive (syms rest) (parse-formals formals) (let* ((e (make-ghil-env e)) (vars (map (lambda (s) (let ((v (make-ghil-var e s 'argument))) (ghil-env-add! e v) v)) syms))) (make- e vars rest (parse-body body e))))))) ;; (@eval-case CLAUSE...) ((@eval-case) (let loop ((clauses args)) (cond ((null? clauses) (make-)) ((or (eq? (caar clauses) '@else) (and (memq 'load-toplevel (caar clauses)) (ghil-env-toplevel? e))) (parse-body (cdar clauses) e)) (else (loop (cdr clauses)))))) (else (error "Unknown primitive:" prim)))) (define (parse-body x e) (make- (map-parse x e))) (define (parse-formals formals) (cond ;; (@lambda x ...) ((symbol? formals) (values (list formals) #t)) ;; (@lambda (x y z) ...) ((list? formals) (values formals #f)) ;; (@lambda (x y . z) ...) ((pair? formals) (let loop ((l formals) (v '())) (if (pair? l) (loop (cdr l) (cons (car l) v)) (values (reverse! (cons l v)) #t)))) (else (error "Invalid formals:" formals)))) (define (identifier-split identifier) (let ((m (string-match "::([^:]*)$" (symbol->string identifier)))) (if m (values (string->symbol (match:prefix m)) (string->symbol (match:substring m 1))) (values #f identifier))))