GuileScript is currently a toy compiler that aims to compile Guile to JavaScript. It currently doesn’t do much, but it might in the future.
Because, why not? Guile is actually a lot of fun and I just got jealous that people could do these sort of cool things with ClojureScript and I couldn’t with Guile. But thanks to GuileScript it is now with gas.
GuileScript leverages Guile’s Compiler Tower. It compiles Guile code into Tree-IL and then compiles Tree-IL into JavaScript.
Tree-IL is the first intermediate language (the main one actually being CPS) that Guile code is actually converted to, so the only thing that I needed to do is figure out how Tree-IL works plus get some inspiration from ClojureScript first commit.
Clone the repository and run:
$ autoreconf -vif $ ./configure $ make $ sudo make install
If you are on macOS you can actually install GuileScript through Guile Homebrew:
$ brew install aconchillo/guile/guilescript
If everything builds and installs fine you can try to compile one of the
provided examples (e.g. examples/fibonacci.gs):
(define (fib n)
(if (<= n 1)
1
(+ (fib (- n 2)) (fib (- n 1)))))$ guilescript examples/fibonacci.gs
which in this case would generate something like:
var fib = function fib(n) {
return ((n<=1) ? 1 : (fib((n-2))+fib((n-1))));
};Too many things, but just to name a few:
- More types: maps, sets…
- More vector and string functions.
- Support formatting in logging functions.
- Integration with Google’s Closure Compiler.
And even long term:
- Modules.
- NodeJS integration.
| GuileScript | JavaScript |
|---|---|
| #nil | null |
| “guile” | “guile” |
| ‘guile | guile |
| #t | true |
| #f | false |
| 234 | 234 |
| 0.5 | 0.5 |
| 1/2 | 0.5 |
| #(1 2 3) | [1,2,3] |
| GuileScript | JavaScript |
|---|---|
| (string-length s) | s.length |
| (string-ref s i) | s[i] |
| GuileScript | JavaScript |
|---|---|
| (vector-length v) | v.length |
| (vector-ref v i) | v[i] |
| (vector-set! v i m) | v[i] = m |
| GuileScript | JavaScript |
|---|---|
| (js-invoke obj ‘method arg1 … argN) | obj.method(arg1,…,argN) |
| (js-new “type” arg1 … argN) | new type(arg1,…,argN) |
| (js-ref obj ‘prop) | obj.prop |
| (js-set! obj ‘prop value) | obj.prop = value |
Note that (js-set! obj prop value) is just a shortcut to (set! (js-ref obj
prop) value).
| GuileScript | JavaScript |
|---|---|
| + - * / < > <= >= | + - * / < > <= >= |
| equal? | === |
| GuileScript | JavaScript |
|---|---|
| abs | Math.abs |
| ceiling | Math.ceil |
| floor | Math.floor |
| max | Math.max |
| min | Math.min |
| round | Math.round |
| GuileScript | JavaScript |
|---|---|
| console-log | console.log |
| console-debug | console.debug |
| console-error | console.error |
| console-warn | console.warn |
| GuileScript | JavaScript |
|---|---|
| (define a 23) | var a = 23; |
| (set! a 45) | a = 45; |
| (begin e1 e2 … eN) | (function () { e1; e2; … return eN; })() |
| (if test then else) | (test ? then : else) |
| (cond ((t1 e1) (t2 e2) (else e3)) | With simple e1, e2, e3: (function () { return (t1 ? e1 : (t2 ? e2 : e3)) })() |
| (when test e1 e2 … eN) | (function () { if (test) { e1; e2; … return eN; } })() |
| (let ((x 0) …) e1 … eN) | (function () { var x = 0; var …; e1; … return eN; })() |
| (let lp ((x 0) (y 0)) e1 … eN) | (function () { var lp = function(x,y) { … return eN; }; return lp(0, 0); })() |
| (lambda (x y) … eN) | (function (x, y) { … return eN; }) |
| (define (f x y) … eN) | var f = function f(x, y) { … return eN; }; |
Macros (define-syntax, syntax-rules, syntax-case) just work out of the box. This is because the Scheme-To-Tree-IL compiler performs macro expansion at the same time it analyzes the code, producing expanded Tree-IL expressions which is what GuileScript actually needs.
Copyright (C) 2022 Aleix Conchillo Flaque <[email protected]>
GuileScript 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 3 of the License, or (at your option) any later version.
GuileScript 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 GuileScript. If not, see https://www.gnu.org/licenses/.