113 lines
4.7 KiB
Scheme
113 lines
4.7 KiB
Scheme
;;;; Rebirth Lisp implemented in Birth and Rebirth Lisp (self-hosting)
|
||
;;;;
|
||
;;;; Copyright (C) 2017, 2018 Mike Gerwitz
|
||
;;;;
|
||
;;;; This file is part of Ulambda Scheme.
|
||
;;;;
|
||
;;;; Ulambda Scheme is free software: you can redistribute it and/or modify
|
||
;;;; it under the terms of the GNU Affero General Public License as
|
||
;;;; published by the Free Software Foundation, either version 3 of the
|
||
;;;; License, 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 Affero General Public License
|
||
;;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
;;;;
|
||
|
||
|
||
|
||
;;; Commentary:
|
||
|
||
;;; THIS IS TEMPORARY CODE that will be REWRITTEN IN ULAMBDA SCHEME after a
|
||
;;; very basic bootstrap is complete. It is retained as an important
|
||
;;; artifact for those who wish to build Ulambda Scheme from scratch without
|
||
;;; using another version of Ulambda itself. This is called "self-hosting".
|
||
;;;
|
||
;;; REBIRTH SHOULD NOT BE USED AS A GENERAL-PURPOSE LISP. It is very
|
||
;;; narrowly tested and absolutely has bugs or misfeatures that were
|
||
;;; explicitly ignored (some of which are explicitly noted).
|
||
;;;
|
||
;;; This is the compiler for Rebirth Lisp---it builds off of Birth by
|
||
;;; first eliminating the need for libprebirth; this allows _all_
|
||
;;; development to happen in a Lisp dialect, which liberates the last
|
||
;;; remaining process that isn't technically self-hosted. So, Rebirth
|
||
;;; completes the raw, self-hosting bootstrapping process.
|
||
;;;
|
||
;;; To continue with the creepy birthing puns, you can consider libprebirth
|
||
;;; to be the umbilical cord. After Birth, it's still attached---here we
|
||
;;; cut it.
|
||
;;;
|
||
;;; Of course, bootstrapping can't end there: we need a fully functioning
|
||
;;; Scheme compiler. Rebirth may as well be called Rerebirth, or
|
||
;;; Rererebirth, or Re*birth, or Reⁿbirth---it is a recursively self-hosting
|
||
;;; compiler. It adds features to itself each time it compiles itself.
|
||
;;;
|
||
;;; Note that we're dealing with a small subset of Scheme here, so certain
|
||
;;; things might be done differently given a proper implementation.
|
||
;;;
|
||
;;; This started as an exact copy of `birth.scm', modified to introduce
|
||
;;; additional features. This is important, since Birth is mostly a 1:1
|
||
;;; translation of the Prebirth compiler and needs to stay that way. This
|
||
;;; fork allows us to vary as much as we want from the initial
|
||
;;; implementation. See the commit history for this file for more
|
||
;;; information as to how it evolved (the first commit is the direct copy
|
||
;;; before actual code changes).
|
||
;;;
|
||
;;; This file follows a narrative (from Birth to Reⁿbirth), but it's more of
|
||
;;; a choose-your-adventure-book-style narrative: order of certain
|
||
;;; definitions unfortunately matters in this simple implementation. For
|
||
;;; example, primitive macros (e.g. `if') must be defined before they are
|
||
;;; used, so those appear at the top of this file, despite their definitions
|
||
;;; not being supported until future passes.
|
||
;;;
|
||
|
||
;;; Code:
|
||
|
||
|
||
|
||
;; So, to begin, goto STEP 0! -------------,
|
||
;; V
|
||
(include "rebirth/es.scm") ;; STEP 2 (start at STEP 0) <--,
|
||
(include "rebirth/relibprebirth.scm") ;; STEP 0 (start here) /
|
||
(include "rebirth/macro.scm") ;; STEP 1 (then go to STEP 2) -`
|
||
|
||
;; The runtime is then initialized and we can proceed with defining the
|
||
;; compiler.
|
||
;;
|
||
;; Most of the compiler has been extracted into a separate file so that it
|
||
;; can be used by other programs; this is necessary because the macro system
|
||
;; uses those definitions, so naturally any program using macros will
|
||
;; require that the compiler definitions be imported.
|
||
(include "rebirth/compiler.scm")
|
||
|
||
|
||
;; Compile Rebirth Lisp AST into ECMAScript.
|
||
;;
|
||
;; The AST can be generated with `parse-lisp'.
|
||
(define (rebirth->ecmascript ast)
|
||
(join "\n\n" (map sexp->es ast)))
|
||
|
||
|
||
;; Compile Rebirth Lisp AST into an ECMAScript program.
|
||
;;
|
||
;; This compiles the AST into ECMAScript using `rebirth->ecmascript' and
|
||
;; then wraps it in a self-executing function to limit scope and create the
|
||
;; toplevel environment.
|
||
(define (rebirth->ecmascript-prog ast env-es)
|
||
;; (note that we no longer depend on libprebirth)
|
||
(string-append "(function(_env){"
|
||
(rebirth->ecmascript ast)
|
||
"})(" env-es ");"))
|
||
|
||
|
||
;; at this point, this program can parse itself and output a CST (sans
|
||
;; whitespace)
|
||
(es:console (rebirth->ecmascript-prog
|
||
(parse-lisp
|
||
(es:file->string "/dev/stdin"))
|
||
(es:empty-env)))
|