7.9 KiB
Where next for guile-prescheme?
- guile repl integration
- script to build each module
- STRT port ps-compiler
- ps-compiler/package-defs.scm
[27/30]
- [X] node
- [X] variable
- [X] primop
- [X] pp-cps
- [X] let-nodes
- [X] check-nodes
- [X] parameters
- [X] set-parameters
- [X] arch
- [X] node-vector
- [X] front
- [X] front-debug
- [X] cps-util
- [X] jump
- [X] simplify
- [-] simplify-internal
- [X] simplify-let
- [X] simplify-join
- [-] simp-patterns
- [X] remove-cells
- [X] flow-values
- [X] comp-util
- [X] expanding-vectors
- [X] transitive
- [X] integer-sets
- [X] strongly-connected
- [X] dominators
- [X] ssa
- [X] compiler-byte-vectors
- [?] annotated-read
- ps-compiler/prescheme/package-defs.scm
[10/27]
- [-] prescheme-compiler
- [-] prescheme-display
- [X] protocol
- [-] prescheme-front-end
- [X] forms
- [-] expand
- [X] ps-primitives
- [-] primitive-data
- [-] eval-node
- [-] flatten
- [-] flatten-internal
- [X] to-cps
- [-] linking
- [X] ps-types
- [X] type-variables
- [X] record-types
- [-] expand-define-record-type
- [-] inference
- [-] inference-internal
- [X] node-types
- [X] ps-primops
- [X] ps-c-primops
- [ ] primop-data
- [ ] c-primop-data
- [ ] external-values
- [ ] c
- [ ] c-internal
- port scheme/bcomp/node.scm
- port scheme/bcomp/schemify.scm
- port scheme/bcomp/package.scm
- port write-one-line from scheme/big/more-port.scm
- review bcomp node vs. ps-compiler node usage
- ps-compiler/package-defs.scm
- prepare some compatibility tests
- replace s48 utilities with rnrs/srfi where possible
- IDEA replace the s48 expander to support modern standard scheme
- IDEA provide an optional Pre-Scheme "standard library"
- write more TODOs
TODO guile repl integration
Currently the "prescheme" language definition is just scheme with a different default environment (aka. the "prelude", the stuff that's imported by default).
In the Guile REPL you can ,L prescheme
to switch language, but it's not very
useful because you stay in the guile-user module, which is Guile's default
environment, not Pre-Scheme's!
You can create a Pre-Scheme module and switch into it with some effort:
(use-modules (system base language))
(set-current-module (default-environment 'prescheme))
,language prescheme
We need to make the process of "give me a Pre-Scheme REPL" easier. Maybe just ship a REPL launcher script which starts up in Pre-Scheme instead of Guile?
TODO script to build each module
We can use guile compile
to get useful warnings:
find -name '*.scm' | xargs -n1 guild compile -W1 -O0 | grep -v '^wrote'
STRT port ps-compiler
Above is just the emulation layer. The real work is the ps-compiler itself, which is written in Scheme 48 (and also Common Lisp apparently). This will involve:
- rewrite s48 interfaces as guile modules
- rewrite macros from explicit renaming to syntax-case
- … and many more unforeseen challenges…
ps-compiler/package-defs.scm [27/30]
[X] node
[X] variable
[X] primop
[X] pp-cps
[X] let-nodes
[X] check-nodes
[X] parameters
[X] set-parameters
[X] arch
[X] node-vector
[X] front
[X] front-debug
[X] cps-util
[X] jump
[X] simplify
[-] simplify-internal
[X] simplify-let
[X] simplify-join
[-] simp-patterns
[X] remove-cells
[X] flow-values
[X] comp-util
[X] expanding-vectors
[X] transitive
[X] integer-sets
[X] strongly-connected
[X] dominators
[X] ssa
[X] compiler-byte-vectors
[?] annotated-read
- the implementation of this package is missing from s48
ps-compiler/prescheme/package-defs.scm [10/27]
[-] prescheme-compiler
[-] prescheme-display
[X] protocol
[-] prescheme-front-end
[X] forms
[-] expand
[X] ps-primitives
[-] primitive-data
[-] eval-node
[-] flatten
[-] flatten-internal
[X] to-cps
[-] linking
[X] ps-types
[X] type-variables
[X] record-types
[-] expand-define-record-type
[-] inference
[-] inference-internal
[X] node-types
[X] ps-primops
[X] ps-c-primops
[ ] primop-data
[ ] c-primop-data
[ ] external-values
[ ] c
[ ] c-internal
DONE port scheme/bcomp/node.scm
TODO port scheme/bcomp/schemify.scm
TODO port scheme/bcomp/package.scm
TODO port write-one-line from scheme/big/more-port.scm
TODO review bcomp node vs. ps-compiler node usage
Scheme48 has two different "node" implementations; one is part of the byte-compiler (bcomp) and one is part of the prescheme compiler (ps-compiler). To compile prescheme code, it is first run through the Scheme48 expander, producing bcomp nodes which are then converted to ps-compiler nodes.
The trouble is that both types of record are called "node", and a number of utility functions share the same name. These differences are handled in the Scheme48 package definitions, but it's possible I've made some errors during porting.
Carefuly review package definitions referencing "nodes" vs "node" interfaces.
TODO prepare some compatibility tests
We need to find collect all the "real-world" Pre-Scheme we can get our hands on, and test that our Guile Pre-Scheme produces identical output to Scheme 48 Pre-Scheme.
Exhibit A is the "hello world" from the manual:
;; https://thintz.com/resources/prescheme-documentation#Example-Pre_002dScheme-compiler-usage
(define (main argc argv)
(if (= argc 2)
(let ((out (current-output-port)))
(write-string "Hello, world, " out)
(write-string (vector-ref argv 1) out)
(write-char #\! out)
(newline out)
0)
(let ((out (current-error-port)))
(write-string "Usage: " out)
(write-string (vector-ref argv 0) out)
(write-string " <user>" out)
(newline out)
(write-string " Greets the world & <user>." out)
(newline out)
-1)))
A bunch of tests are included in scheme48-1.9.2/ps-compiler/prescheme/test. Nice!
TODO test infrastucture (SRFI-64?)
TODO test coverage of let-nodes
TODO replace s48 utilities with rnrs/srfi where possible
The initial port of ps-compiler tries to minimise changes from the original source, this has meant porting a decent collection of supporting utility functions and macros from Scheme 48. After the initial port is complete, we should replace these utilities with standardised equivalents.
This will reduce the amount of code we need to maintain, make it easier for people with experience in other contemporary scheme projects to contribute, and ease future work to port ps-compiler to other scheme implementations.
IDEA replace the s48 expander to support modern standard scheme
Pre-Scheme relies on the Scheme 48 macro expander to pre-process source code before translating it into the intermediate representation used by the compiler.
John Cowan has suggested replacing the Scheme 48 expander with Unsyntax (https://www.unsyntax.org/). Unsyntax supports R7RS with a number of extensions (including a variety of macro systems), expanding to a minimal dialect of R7RS-small. It's also implemented in R7RS-small, so is easily portable across scheme implementations.
To integrate the new expander, additional work will be required to resolve mismatches between Unsyntax's minimal dialect and Pre-Scheme's minimal dialect.
This would significantly reduce the amount of code we need to maintain, go a long way towards modernising the Pre-Scheme language, and ease future work to port ps-compiler to other scheme implementations.
This would also probably be a backwards-incompatible change to Pre-Scheme, going beyond the scope implied by calling this project a "port". We should discuss this with Richard Kelsey, Jonathan Rees, and Michael Sperber and get their permission to continue under the Pre-Scheme name, or possibly rename the project.
IDEA provide an optional Pre-Scheme "standard library"
Pre-Scheme supports a very minimal dialect of scheme, which is basically the subset of scheme features that can be directly translated to C. This excludes many features that a scheme programmer would expect, such as lists.
This minimalism is necessary to satisfy Pre-Scheme's goal of offering a low-level, zero-overhead, zero-runtime scheme-like language, and that purity shouldn't be compromised. It should always be possible to write in a minimal dialect that compiles directly to standard portable C.
However, to make Pre-Scheme more attractive and useful to a wider variety of programmers, we should provide a completely optional set of standard libraries, written in Pre-Scheme, to extend the base language with commonly-used functionality. These libraries should offer APIs as close to standard scheme as possible (ie. based on RNRS/SRFI documents), but be implemented in a way that's familiar to C programmers, with unsurprising runtime characteristics.
The libraries should cover things like:
- POSIX processes, threads, mutexes, shared memory, etc.
- lists
- hash-tables
- CLOS-alike
- …?
One challenge will be to decide how to support generic data-structures. Will it be sufficient to offer a set of macros which expand into concrete definitions, like the C++ STL but in scheme?
We should discuss this with Richard Kelsey, Jonathan Rees, and Michael Sperber to investigate whether there were any previous efforts in this direction. We should also look at other scheme-likes and low-level lisps for inspiration on what functionality could be included, and consult with the wider scheme community to learn about as much prior art as possible.