1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-19 19:20:23 +02:00

add parsers and unparser for ghil; ,language ghil works now

* module/system/repl/common.scm (repl-print): Slightly refine the meaning
  of "language-printer": a language printer prints an expression of a
  language, not the result of evaluation. `write' prints values.

* module/language/ghil/spec.scm (ghil): Define a language printer, and a
  translator for turning s-expressions (not scheme, mind you) into GHIL.

* module/language/scheme/translate.scm (quote, quasiquote): Add some
  #:keyword action, so that we can (quote #:keywords).

* module/system/base/language.scm (<language>):
* module/system/base/compile.scm (read-file-in): Don't require that a
  language have a read-file; instead error when read-file is called.
  (compile-passes, compile-in): Refactor to call a helper method to turn
  the language + set of options into a set of compiler passes.

* module/system/base/syntax.scm (define-type): Allow the type to be a
  list, with the car being the name and the cdr being keyword options.
  Interpret #:printer as a printer, and pass it down to...
  (define-record): Here.

* module/system/il/ghil.scm (print-ghil, <ghil>): New printer for GHIL,
  yay!
  (parse-ghil, unparse-ghil): New lovely functions. Will document them in
  the manual.
This commit is contained in:
Andy Wingo 2008-11-11 22:52:24 +01:00
parent f698d111b4
commit f38624b349
7 changed files with 225 additions and 184 deletions

View file

@ -21,12 +21,21 @@
(define-module (language ghil spec) (define-module (language ghil spec)
#:use-module (system base language) #:use-module (system base language)
#:use-module (system il ghil)
#:export (ghil)) #:export (ghil))
(define (write-ghil exp . port)
(apply write (unparse-ghil exp) port))
(define (translate x e)
(call-with-ghil-environment e '()
(lambda (env vars)
(make-ghil-lambda env #f vars #f '() (parse-ghil env x)))))
(define-language ghil (define-language ghil
#:title "Guile High Intermediate Language (GHIL)" #:title "Guile High Intermediate Language (GHIL)"
#:version "0.3" #:version "0.3"
#:reader read #:reader read
#:printer write #:printer write-ghil
;; #:environment (make-vmodule) #:translator translate
) )

View file

@ -136,11 +136,11 @@
(define-scheme-translator quote (define-scheme-translator quote
;; (quote OBJ) ;; (quote OBJ)
((,obj) (make-ghil-quote e l obj))) ((,obj) (make-ghil-quote e l #:obj obj)))
(define-scheme-translator quasiquote (define-scheme-translator quasiquote
;; (quasiquote OBJ) ;; (quasiquote OBJ)
((,obj) (make-ghil-quasiquote e l (trans-quasiquote e l obj 0)))) ((,obj) (make-ghil-quasiquote e l #:exp (trans-quasiquote e l obj 0))))
(define-scheme-translator define (define-scheme-translator define
;; (define NAME VAL) ;; (define NAME VAL)

View file

@ -30,6 +30,7 @@
#:use-module (system vm vm) ;; for compile-time evaluation #:use-module (system vm vm) ;; for compile-time evaluation
#:use-module (ice-9 regex) #:use-module (ice-9 regex)
#:use-module (ice-9 optargs) #:use-module (ice-9 optargs)
#:use-module ((srfi srfi-1) #:select (fold))
#:export (syntax-error compile-file load-source-file load-file #:export (syntax-error compile-file load-source-file load-file
*current-language* *current-language*
compiled-file-name compiled-file-name
@ -197,27 +198,35 @@ time. Useful for supporting some forms of dynamic compilation. Returns
;;; ;;;
(define (read-file-in file lang) (define (read-file-in file lang)
(call-with-input-file file (language-read-file lang))) (call-with-input-file file (or (language-read-file lang)
(error "language has no #:read-file" lang))))
;;; FIXME: fold run-pass x (compile-passes lang opts)
(define (compile-passes lang opts)
(let lp ((passes (list
(language-expander lang)
(language-translator lang)
(lambda (x e) (apply compile-il x e opts))
(lambda (x e) (apply assemble x e opts))))
(keys '(#f #:e #:t #:c))
(out '()))
(if (or (null? keys)
(and (car keys) (memq (car keys) opts)))
(reverse! out)
(lp (cdr passes) (cdr keys)
(if (car passes)
(cons (car passes) out)
out)))))
(define (compile-in x e lang . opts) (define (compile-in x e lang . opts)
(save-module-excursion (save-module-excursion
(lambda () (lambda ()
(catch 'result (and=> (cenv-module e) set-current-module)
(lambda () (let ((env (cenv-ghil-env e)))
(and=> (cenv-module e) set-current-module) (fold (lambda (pass exp)
(set! e (cenv-ghil-env e)) (pass exp env))
;; expand x
(set! x ((language-expander lang) x e)) (compile-passes lang opts))))))
(if (memq #:e opts) (throw 'result x))
;; translate
(set! x ((language-translator lang) x e))
(if (memq #:t opts) (throw 'result x))
;; compile
(set! x (apply compile-il x e opts))
(if (memq #:c opts) (throw 'result x))
;; assemble
(apply assemble x e opts))
(lambda (key val) val)))))
;;; ;;;
;;; ;;;

View file

@ -31,9 +31,10 @@
;;; Language class ;;; Language class
;;; ;;;
(define-record (<language> name title version reader printer read-file (define-record (<language> name title version reader printer
(expander (lambda (x e) x)) (read-file #f)
(translator (lambda (x e) x)) (expander #f)
(translator #f)
(evaluator #f) (evaluator #f)
(environment #f) (environment #f)
)) ))

View file

@ -29,7 +29,12 @@
;;; ;;;
(define-macro (define-type name . rest) (define-macro (define-type name . rest)
`(begin ,@(map (lambda (def) `(define-record ,def)) rest))) (let ((name (if (pair? name) (car name) name))
(opts (if (pair? name) (cdr name) '())))
(let ((printer (kw-arg-ref opts #:printer)))
`(begin ,@(map (lambda (def) `(define-record ,def
,@(if printer (list printer) '())))
rest)))))
;;; ;;;
@ -39,13 +44,14 @@
(define (symbol-trim-both sym pred) (define (symbol-trim-both sym pred)
(string->symbol (string-trim-both (symbol->string sym) pred))) (string->symbol (string-trim-both (symbol->string sym) pred)))
(define-macro (define-record def) (define-macro (define-record def . printer)
(let* ((name (car def)) (slots (cdr def)) (let* ((name (car def)) (slots (cdr def))
(slot-names (map (lambda (slot) (if (pair? slot) (car slot) slot)) (slot-names (map (lambda (slot) (if (pair? slot) (car slot) slot))
slots)) slots))
(stem (symbol-trim-both name (list->char-set '(#\< #\>))))) (stem (symbol-trim-both name (list->char-set '(#\< #\>)))))
`(begin `(begin
(define ,name (make-record-type ,(symbol->string name) ',slot-names)) (define ,name (make-record-type ,(symbol->string name) ',slot-names
,@printer))
(define ,(symbol-append 'make- stem) (define ,(symbol-append 'make- stem)
(let ((slots (list ,@(map (lambda (slot) (let ((slots (list ,@(map (lambda (slot)
(if (pair? slot) (if (pair? slot)

View file

@ -20,7 +20,8 @@
;;; Code: ;;; Code:
(define-module (system il ghil) (define-module (system il ghil)
#:use-syntax (system base syntax) #:use-module (system base syntax)
#:use-module (system base pmatch)
#:use-module (ice-9 regex) #:use-module (ice-9 regex)
#:export #:export
(<ghil-void> make-ghil-void ghil-void? (<ghil-void> make-ghil-void ghil-void?
@ -100,14 +101,19 @@
ghil-env-reify ghil-env-dereify ghil-env-reify ghil-env-dereify
ghil-var-is-bound? ghil-var-for-ref! ghil-var-for-set! ghil-var-define! ghil-var-is-bound? ghil-var-for-ref! ghil-var-for-set! ghil-var-define!
ghil-var-at-module! ghil-var-at-module!
call-with-ghil-environment call-with-ghil-bindings)) call-with-ghil-environment call-with-ghil-bindings
parse-ghil unparse-ghil))
;;; ;;;
;;; Parse tree ;;; Parse tree
;;; ;;;
(define-type <ghil> (define (print-ghil x port)
(format port "#<ghil ~s>" (unparse-ghil x)))
(define-type (<ghil> #:printer print-ghil)
;; Objects ;; Objects
(<ghil-void> env loc) (<ghil-void> env loc)
(<ghil-quote> env loc obj) (<ghil-quote> env loc obj)
@ -309,156 +315,162 @@
;;; Parser ;;; Parser
;;; ;;;
;;; (define-public (parse-ghil x e) (define (location x)
;;; (parse `(@lambda () ,x) (make-ghil-mod e))) (and (pair? x)
;;; (let ((props (source-properties x)))
;;; (define (parse x e) (and (not (null? props))
;;; (cond ((pair? x) (parse-pair x e)) (vector (assq-ref props 'line)
;;; ((symbol? x) (assq-ref props 'column)
;;; (let ((str (symbol->string x))) (assq-ref props 'filename))))))
;;; (case (string-ref str 0)
;;; ((#\@) (error "Invalid use of IL primitive" x)) (define (parse-quasiquote e x level)
;;; ((#\:) (let ((sym (string->symbol (substring str 1)))) (cond ((not (pair? x)) x)
;;; (<ghil-quote> (symbol->keyword sym)))) ((memq (car x) '(unquote unquote-splicing))
;;; (else (<ghil-ref> e (ghil-lookup e x)))))) (let ((l (location x)))
;;; (else (<ghil-quote> x)))) (pmatch (cdr x)
;;; ((,obj)
;;; (define (map-parse x e) (cond
;;; (map (lambda (x) (parse x e)) x)) ((zero? level)
;;; (if (eq? (car x) 'unquote)
;;; (define (parse-pair x e) (make-ghil-unquote e l (parse-ghil e obj))
;;; (let ((head (car x)) (tail (cdr x))) (make-ghil-unquote-splicing e l (parse-ghil e obj))))
;;; (if (and (symbol? head) (eq? (string-ref (symbol->string head) 0) #\@)) (else
;;; (if (ghil-primitive-macro? head) (list (car x) (parse-quasiquote e obj (1- level))))))
;;; (parse (apply (ghil-macro-expander head) tail) e) (else (syntax-error l (format #f "bad ~A" (car x)) x)))))
;;; (parse-primitive head tail e)) ((eq? (car x) 'quasiquote)
;;; (<ghil-call> e (parse head e) (map-parse tail e))))) (let ((l (location x)))
;;; (pmatch (cdr x)
;;; (define (parse-primitive prim args e) ((,obj) (list 'quasiquote (parse-quasiquote e obj (1+ level))))
;;; (case prim (else (syntax-error l (format #f "bad ~A" (car x)) x)))))
;;; ;; (@ IDENTIFIER) (else (cons (parse-quasiquote e (car x) level)
;;; ((@) (parse-quasiquote e (cdr x) level)))))
;;; (match args
;;; (() (define (parse-ghil env exp)
;;; (<ghil-ref> e (make-ghil-var '@ '@ 'module))) (let ((loc (location exp))
;;; ((identifier) (retrans (lambda (x) (parse-ghil env x))))
;;; (receive (module name) (identifier-split identifier) (pmatch exp
;;; (<ghil-ref> e (make-ghil-var module name 'module)))))) (,exp (guard (symbol? exp))
;;; (make-ghil-ref env #f (ghil-var-for-ref! env exp)))
;;; ;; (@@ OP ARGS...)
;;; ((@@) (,exp (guard (not (pair? exp)))
;;; (match args (make-ghil-quote #:env env #:loc #f #:obj exp))
;;; ((op . args)
;;; (<ghil-inline> op (map-parse args e))))) (('quote ,exp) (make-ghil-quote #:env env #:loc loc #:obj exp))
;;;
;;; ;; (@void) ((void) (make-ghil-void env loc))
;;; ((@void)
;;; (match args ((lambda ,syms ,rest ,meta . ,body)
;;; (() (<ghil-void>)))) (call-with-ghil-environment env syms
;;; (lambda (env vars)
;;; ;; (@quote OBJ) (make-ghil-lambda env loc vars rest meta
;;; ((@quote) (parse-ghil env `(begin ,@body))))))
;;; (match args
;;; ((obj) ((begin . ,body)
;;; (<ghil-quote> obj)))) (make-ghil-begin env loc (map retrans body)))
;;;
;;; ;; (@define NAME VAL) ((bind ,syms ,exprs . ,body)
;;; ((@define) (let ((vals (map retrans exprs)))
;;; (match args (call-with-ghil-bindings env syms
;;; ((name val) (lambda (vars)
;;; (let ((v (ghil-lookup e name))) (make-ghil-bind env loc vars vals (retrans `(begin ,@body)))))))
;;; (<ghil-set> e v (parse val e))))))
;;; ((bindrec ,syms ,exprs . ,body)
;;; ;; (@set! NAME VAL) (call-with-ghil-bindings env syms
;;; ((@set!) (lambda (vars)
;;; (match args (let ((vals (map (lambda (exp) (parse-ghil env exp)) exprs)))
;;; ((name val) (make-ghil-bind env loc vars vals (retrans `(begin ,@body)))))))
;;; (let ((v (ghil-lookup e name)))
;;; (<ghil-set> e v (parse val e)))))) ((set! ,sym ,val)
;;; (make-ghil-set env loc (ghil-var-for-set! env sym) (retrans val)))
;;; ;; (@if TEST THEN [ELSE])
;;; ((@if) ((define ,sym ,val)
;;; (match args (make-ghil-define env loc (ghil-var-define! env sym) (retrans val)))
;;; ((test then)
;;; (<ghil-if> (parse test e) (parse then e) (<ghil-void>))) ((if ,test ,then ,else)
;;; ((test then else) (make-ghil-if env loc (retrans test) (retrans then) (retrans else)))
;;; (<ghil-if> (parse test e) (parse then e) (parse else e)))))
;;; ((and . ,exps)
;;; ;; (@begin BODY...) (make-ghil-and env loc (map retrans exps)))
;;; ((@begin)
;;; (parse-body args e)) ((or . ,exps)
;;; (make-ghil-or env loc (map retrans exps)))
;;; ;; (@let ((SYM INIT)...) BODY...)
;;; ((@let) ((mv-bind ,syms ,rest ,producer . ,body)
;;; (match args (call-with-ghil-bindings env syms
;;; ((((sym init) ...) body ...) (lambda (vars)
;;; (let* ((vals (map-parse init e)) (make-ghil-mv-bind env loc (retrans producer) vars rest
;;; (vars (map (lambda (s) (map retrans body)))))
;;; (let ((v (make-ghil-var e s 'local)))
;;; (ghil-env-add! e v) v)) ((call ,proc . ,args)
;;; sym)) (make-ghil-call env loc (retrans proc) (map retrans args)))
;;; (body (parse-body body e)))
;;; (for-each (lambda (v) (ghil-env-remove! e v)) vars) ((mv-call ,producer . ,consumer)
;;; (<ghil-bind> e vars vals body))))) (make-ghil-mv-call env loc (retrans producer) (retrans consumer)))
;;;
;;; ;; (@letrec ((SYM INIT)...) BODY...) ((inline ,op . ,args)
;;; ((@letrec) (make-ghil-inline env loc op (map retrans args)))
;;; (match args
;;; ((((sym init) ...) body ...) ((values . ,values)
;;; (let* ((vars (map (lambda (s) (make-ghil-values env loc (map retrans values)))
;;; (let ((v (make-ghil-var e s 'local)))
;;; (ghil-env-add! e v) v)) ((values* . ,values)
;;; sym)) (make-ghil-values env loc (map retrans values)))
;;; (vals (map-parse init e))
;;; (body (parse-body body e))) ((compile-time-environment)
;;; (for-each (lambda (v) (ghil-env-remove! e v)) vars) (make-ghil-reified-env env loc))
;;; (<ghil-bind> e vars vals body)))))
;;; ((quasiquote ,exp)
;;; ;; (@lambda FORMALS BODY...) (make-ghil-quasiquote env loc #:exp (parse-quasiquote env exp 0)))
;;; ((@lambda)
;;; (match args (else
;;; ((formals . body) (error "unrecognized GHIL" exp)))))
;;; (receive (syms rest) (parse-formals formals)
;;; (let* ((e (make-ghil-env e)) (define (unparse-ghil ghil)
;;; (vars (map (lambda (s) (record-case ghil
;;; (let ((v (make-ghil-var e s 'argument))) ((<ghil-void> env loc)
;;; (ghil-env-add! e v) v)) '(void))
;;; syms))) ((<ghil-quote> env loc obj)
;;; (<ghil-lambda> e vars rest (parse-body body e))))))) `(quote ,obj))
;;; ((<ghil-quasiquote> env loc exp)
;;; ;; (@eval-case CLAUSE...) `(quasiquote ,(map unparse-ghil exp)))
;;; ((@eval-case) ((<ghil-unquote> env loc exp)
;;; (let loop ((clauses args)) `(unquote ,(unparse-ghil exp)))
;;; (cond ((null? clauses) (<ghil-void>)) ((<ghil-unquote-splicing> env loc exp)
;;; ((or (eq? (caar clauses) '@else) `(unquote-splicing ,(unparse-ghil exp)))
;;; (and (memq 'load-toplevel (caar clauses)) ;; Variables
;;; (ghil-env-toplevel? e))) ((<ghil-ref> env loc var)
;;; (parse-body (cdar clauses) e)) (ghil-var-name var))
;;; (else ((<ghil-set> env loc var val)
;;; (loop (cdr clauses)))))) `(set! ,(ghil-var-name var) ,(unparse-ghil val)))
;;; ((<ghil-define> env loc var val)
;;; (else (error "Unknown primitive:" prim)))) `(define ,(ghil-var-name var) ,(unparse-ghil val)))
;;; ;; Controls
;;; (define (parse-body x e) ((<ghil-if> env loc test then else)
;;; (<ghil-begin> (map-parse x e))) `(if ,(unparse-ghil test) ,(unparse-ghil then) ,(unparse-ghil else)))
;;; ((<ghil-and> env loc exps)
;;; (define (parse-formals formals) `(and ,@(map unparse-ghil exps)))
;;; (cond ((<ghil-or> env loc exps)
;;; ;; (@lambda x ...) `(or ,@(map unparse-ghil exps)))
;;; ((symbol? formals) (values (list formals) #t)) ((<ghil-begin> env loc exps)
;;; ;; (@lambda (x y z) ...) `(begin ,@(map unparse-ghil exps)))
;;; ((list? formals) (values formals #f)) ((<ghil-bind> env loc vars vals body)
;;; ;; (@lambda (x y . z) ...) `(bind ,(map ghil-var-name vars) ,(map unparse-ghil vals)
;;; ((pair? formals) ,@(map unparse-ghil body)))
;;; (let loop ((l formals) (v '())) ((<ghil-mv-bind> env loc producer vars rest body)
;;; (if (pair? l) `(mv-bind ,(map ghil-var-name vars) ,rest
;;; (loop (cdr l) (cons (car l) v)) ,(unparse-ghil producer) ,@(map unparse-ghil body)))
;;; (values (reverse! (cons l v)) #t)))) ((<ghil-lambda> env loc vars rest meta body)
;;; (else (error "Invalid formals:" formals)))) `(lambda ,(map ghil-var-name vars) ,rest ,meta
;;; ,(unparse-ghil body)))
;;; (define (identifier-split identifier) ((<ghil-call> env loc proc args)
;;; (let ((m (string-match "::([^:]*)$" (symbol->string identifier)))) `(call ,(unparse-ghil proc) ,@(map unparse-ghil args)))
;;; (if m ((<ghil-mv-call> env loc producer consumer)
;;; (values (string->symbol (match:prefix m)) `(mv-call ,(unparse-ghil producer) ,(unparse-ghil consumer)))
;;; (string->symbol (match:substring m 1))) ((<ghil-inline> env loc inline args)
;;; (values #f identifier)))) `(inline ,inline (map unparse-ghil args)))
((<ghil-values> env loc values)
`(values (map unparse-ghil values)))
((<ghil-values*> env loc values)
`(values* (map unparse-ghil values)))
((<ghil-reified-env> env loc)
`(compile-time-environment))))

View file

@ -78,7 +78,11 @@
(define (repl-print repl val) (define (repl-print repl val)
(if (not (eq? val *unspecified*)) (if (not (eq? val *unspecified*))
(begin (begin
((language-printer (repl-language repl)) val) ;; The result of an evaluation is representable in scheme, and
;; should be printed with the generic printer, `write'. The
;; language-printer is something else: it prints expressions of
;; a given language, not the result of evaluation.
(write val)
(newline)))) (newline))))
(define (repl-option-ref repl key) (define (repl-option-ref repl key)