176 lines
5.8 KiB
Scheme
176 lines
5.8 KiB
Scheme
;; -*- mode: scheme; coding: utf-8 -*-
|
|
;; Copyright © 2019 G. Weinholt
|
|
;; SPDX-License-Identifier: MIT
|
|
|
|
;; Permission is hereby granted, free of charge, to any person obtaining a
|
|
;; copy of this software and associated documentation files (the "Software"),
|
|
;; to deal in the Software without restriction, including without limitation
|
|
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
;; and/or sell copies of the Software, and to permit persons to whom the
|
|
;; Software is furnished to do so, subject to the following conditions:
|
|
|
|
;; The above copyright notice and this permission notice shall be included in
|
|
;; all copies or substantial portions of the Software.
|
|
|
|
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
;; DEALINGS IN THE SOFTWARE.
|
|
#!r6rs
|
|
|
|
;; RnRS writer
|
|
|
|
(library (laesare writer)
|
|
(export
|
|
put-token
|
|
make-writer writer?
|
|
writer-port writer-filename
|
|
writer-mode writer-mode-set!)
|
|
(import
|
|
(rnrs (6)))
|
|
|
|
(define-record-type writer
|
|
(fields port filename
|
|
(mutable mode))
|
|
(sealed #t) (opaque #f)
|
|
(nongenerative writer-v0-d2dafa98-4344-400d-ba4d-633e6a1e9133)
|
|
(protocol
|
|
(lambda (p)
|
|
(lambda (port filename)
|
|
(p port filename 'rnrs)))))
|
|
|
|
(define (assert-mode writer modes type token)
|
|
(unless (memq (writer-mode writer) modes)
|
|
(assertion-violation 'put-token
|
|
"Token type is not supported in this mode"
|
|
type token (writer-mode writer))))
|
|
|
|
(define r7rs-char-names
|
|
'((#\nul . "null")
|
|
(#\alarm . "alarm")
|
|
(#\backspace . "backspace")
|
|
(#\tab . "tab")
|
|
(#\linefeed . "newline")
|
|
(#\vtab . #f)
|
|
(#\page . #f)
|
|
(#\return . "return")
|
|
(#\esc . "escape")
|
|
(#\space . "space")
|
|
(#\delete . "delete")))
|
|
|
|
(define (put-token writer type token)
|
|
(let ((p (writer-port writer)))
|
|
(case type
|
|
((identifier)
|
|
;; FIXME: quoting according to R7RS
|
|
(write token p))
|
|
((value)
|
|
(cond
|
|
((and (eq? (writer-mode writer) 'r7rs) (assv token r7rs-char-names))
|
|
=> (lambda (name)
|
|
(cond ((cdr name)
|
|
(put-string p "#\\")
|
|
(put-string p (cdr name)))
|
|
(else
|
|
(put-string p "#\\x")
|
|
(put-string p (string-downcase (number->string (char->integer token) 16)))))))
|
|
((eqv? token #\linefeed)
|
|
(put-string p "#\\linefeed"))
|
|
((eqv? token #\esc)
|
|
(if (eq? (writer-mode writer) 'r6rs)
|
|
(put-string p "#\\esc") ;workaround for Larceny 1.3
|
|
(put-string p "#\\x1b")))
|
|
((and (char? token) (memq (char-general-category token) '(Cf Zp So)))
|
|
(put-string p "#\\x")
|
|
(put-string p (string-downcase (number->string (char->integer token) 16))))
|
|
(else
|
|
(write token p))))
|
|
((bytevector)
|
|
(case (writer-mode writer)
|
|
((r6rs) (put-string p "#vu8("))
|
|
((r7rs) (put-string p "#u8("))
|
|
(else
|
|
(assertion-violation 'put-token "Bytevectors are not supported in this mode"
|
|
type token (writer-mode writer)))))
|
|
((directive)
|
|
(put-string p "#!")
|
|
(display token p)
|
|
(case token
|
|
((r6rs) (writer-mode-set! writer 'r6rs))
|
|
((r7rs) (writer-mode-set! writer 'r7rs))
|
|
(else (values))))
|
|
|
|
((openb)
|
|
(case (writer-mode writer)
|
|
((r6rs) (put-char p #\[))
|
|
(else (put-char p #\())))
|
|
((closeb)
|
|
(case (writer-mode writer)
|
|
((r6rs) (put-char p #\]))
|
|
(else (put-char p #\)))))
|
|
|
|
((abbrev)
|
|
(case token
|
|
((quote) (put-string p "'"))
|
|
((quasiquote) (put-string p "`"))
|
|
((unquote) (put-string p ","))
|
|
((unquote-splicing) (put-string p ",@"))
|
|
((syntax)
|
|
(assert-mode writer '(rnrs r6rs) type token)
|
|
(put-string p "#'"))
|
|
((quasisyntax)
|
|
(assert-mode writer '(rnrs r6rs) type token)
|
|
(put-string p "#`"))
|
|
((unsyntax)
|
|
(assert-mode writer '(rnrs r6rs) type token)
|
|
(put-string p "#,"))
|
|
((unsyntax-splicing)
|
|
(assert-mode writer '(rnrs r6rs) type token)
|
|
(put-string p "#,@"))
|
|
(else
|
|
(assertion-violation 'put-token "Unrecognized abbreviation"
|
|
type token))))
|
|
|
|
((label reference)
|
|
(assert-mode writer '(rnrs r7rs) type token)
|
|
(put-string p "#")
|
|
(display token p)
|
|
(if (eq? type 'label)
|
|
(put-string p "=")
|
|
(put-string p "#")))
|
|
|
|
;; Mode independent
|
|
|
|
((dot)
|
|
(put-char p #\.))
|
|
((inline-comment)
|
|
(let ((atmosphere (car token))
|
|
(datum (cdr token)))
|
|
(put-string p "#;")
|
|
(for-each (lambda (t+t)
|
|
(put-token writer (car t+t) (cdr t+t)))
|
|
atmosphere)
|
|
(write datum p)))
|
|
((whitespace)
|
|
(put-string p token))
|
|
((openp) (put-char p #\())
|
|
((closep) (put-char p #\)))
|
|
((vector) (put-string p "#("))
|
|
((shebang)
|
|
(put-string p "#!")
|
|
(put-string p (caddr token))
|
|
(put-char p #\newline))
|
|
((comment)
|
|
(put-char p #\;)
|
|
(put-string p token))
|
|
((nested-comment)
|
|
(put-string p "#|")
|
|
(put-string p token)
|
|
(put-string p "|#"))
|
|
(else
|
|
(assertion-violation 'put-token "Unrecognized token type"
|
|
type token))))))
|