scheme2js
Florian Loitsch
17 July 2011
Version 20110717
scheme2js
- compiles Scheme programs to JavaScript
Table of Contents
scheme2js
[-h|--help]
[--version]
[-v|--verbose]
[--js-dot-notation]
[--bigloo-modules]
[--compress]
[--infotron]
[--encapsulate-modules]
[--export-globals]
[--allow-unresolved]
[--js-this]
[--js-return]
[--statics-suffix suffix]
[--constant-runtime]
[--indent width]
[-O level]
[--tailrec]
[--while]
[--inlining]
[--max-inline-size size]
[--rec-inline-nb nb]
[--var-elimination]
[--propagation]
[--constant-propagation]
[--bigloo-runtime-eval]
[--correct-modulo]
[--optimize-calls]
[--optimize-boolify]
[--optimize-consts]
[--trampoline]
[--max-tail-depth depth]
[--suspend-resume]
[--call/cc]
[-g]
[-d stage]
[-I dir]
-o outfile
infile
scheme2js
takes infile
and writes to outfile.
If
in/outfile
is '-'
stdin/out is used. The input must be a
Scheme file. scheme2js
translates the program into JavaScript.
All boolean options can be prefixed with 'no-',
to deactivate them. For
example '--no-js-dot-notation'
would disable JavaScript's dot-notation.
Options are evaluated in order. If conflicting options are given, the last
entry wins. This allows to use -O
and then to adjust the values subsequently.
- -o outfile
- Write output into outfile.
If outfile
equals "-"
then the result will be printed to stdout.
- -I dir
- Add dir
to Include-path. This path will be searched for
imported modules.
- infile
- The Scheme Input-file.
- --compress
- Compress the generated output. Nearly all unnecessary
spaces are removed.
- -h|--help
- Prints a help-message.
- --version
- Prints the version of scheme2js.
- -v|--verbose
- Activate verbose output.
- --js-dot-notation
- Allow JavaScript dot-notation in
source-file. This allows access to object-properties like o.x.
- --infotron
- Activates support for Infotrons. See Section Infotron
for more details.
- --bigloo-modules
- Uses Bigloo style module declarations (see
the Modules section below).
- --encapsulate-modules
- Wrap the module (the compiled file) into an
anonymous function. Global variables that are not exported (for instance
top-level 'let'-variables)
thus do not pollute the JavaScript
top-level.
- --export-globals
- Export all global variables. Variables
introduced by global 'let's
are not affected by this flag. By default
all global variables of files without 'module'-clause are exported. Files with
'module'-clause do only export variables declared in the module-clause.
- --allow-unresolved
- Variables that are unresolved are supposed to
be JavaScript variables or exported variables from other modules. By default
files without 'module'-clause allow unresolved. Files with a 'module'-clause
yield error-messages on unknown variables.
- --js-this
- Allow the access of JavaScript's 'this'
inside
Scheme procedures.
- --js-return
- Introduces a special form: 'return',
which has
the same semantics as JavaScript's 'return'.
- --constant-runtime
- Assume runtime is constant. Disallows
assignments to runtime-functions. When enabled the interface files
runtime_interface.js
and
runtime_interface_callcc.js
are not needed anymore.
- --statics-suffix suffix
- Sets the suffix for
static variables. Static variables are global variables that are not
exported. This avoids name-clashes with non-exported variables of different
modules. If a module is encapsulated, then this flag has no effect. By default
'_' followed by the file-name without extension is used (which is the same as
the module's name).
- --indent width
- Sets the indentation width for the
produced code.
- --tailrec
- Transform (obvious) tail-recursive loops into
'while'-loops.
- --while
- Searches for common loop-pattern. Improves the generated
'while'-loops.
- --inlining
- Inlines (small) functions, and functions, that are only
used once (-> no code size increase).
- --max-inline-size size
- Only inline functions smaller
than size.
The calculated size is a rough estimate of the final
code-size. Small functions have a size of about 30.
- --rec-inline-nb nb
- Inline at most nb
nested
functions. That is, if a function has been inlined, continue inlining inside
the inlined function's body, but only nb
times. A value of 1 forbits
inlining inside the body of an inlined function. Functions that are only called
at one location are exempted from this limitation.
- --var-elimination
- Reduce the number of variables, by substituting
variables. '(let ((x expr)) (let ((y x)) ....))'
becomes
'(let ((y expr)) ...)'.
- --propagation
- Enables constant-propagation. Whenever possible
var-references are propagated too: if variable 'x'
has the same value as
'y'
the references to 'x'
are replaced by a reference to
'y'.
- --constant-propagation
- Propagates constant variables. Suppose
'x'
is initialized with a constant value 'c'.
Then all references
to 'x'
are replaced by 'c'
- --bigloo-runtime-eval
- Use a Bigloo 'eval' during compilation when
a constant expressions (for instance '(+ 2 5)) is encountered. Only a limited
'safe' subset of runtime-functions are evaluated this way. However the result
might not be the same as if evaluated at runtime. For example (/ 5 2) would
yield 2 when evaluated by Bigloo, but yields 2.5 when evaluated at runtime.
- --correct-modulo
- The semantics of Scheme's and JavaScript's modulo
differ. With this flag the more expensive R5RS modulo is simulated in
JavaScript. Only of relevance when --optimize-calls
is activated.
- --optimize-calls
- Peephole optimization of small
runtime-functions. Runtime functions like '+',
'null?',
etc. are
directly inlined with their JavaScript equivalent and do not invoke any
function-call.
- --optimize-boolify
- During boolification do not test against
'false'
if the expression is known to be of type bool.
- --optimize-consts
- Store explicit constants (like lists and
vectors) in global variables, so they are not recreated.
- -O level
- Sets the optimization level (default is
-O 1).
Each optimization level enables/disables several flags at once:
- -O0
- --no-tailrec
--no-inlining
--no-inline-runtime
--no-constant-runtime
--no-propagation
--no-constant-propagation
--no-while
--correct-modulo
--no-optimize-calls
--no-optimize-boolify
--no-optimize-set!
--max-tail-depth 40
--no-var-elimination
--no-optimize-consts
--no-bigloo-runtime-eval
- -O1
- --tailrec
--inlining
--max-rec-inline 3
--max-inline-size 30
--inline-runtime
--constant-runtime
--propagation
--constant-propagation
--while
--no-correct-modulo
--optimize-calls
--optimize-boolify
--optimize-set!
--max-tail-depth 40
--var-elimination
--optimize-consts
--no-bigloo-runtime-eval
- -O2
- --tailrec
--inlining
--max-rec-inline 1
--max-inline-size 15
--no-inline-runtime
--constant-runtime
--propagation
--constant-propagation
--while
--no-correct-modulo
--optimize-calls
--optimize-boolify
--optimize-set!
--max-tail-depth 40
--var-elimination
--optimize-consts
--bigloo-runtime-eval
- -O3
- --tailrec
--inlining
--max-rec-inline 4
--max-inline-size 45
--inline-runtime
--constant-runtime
--propagation
--constant-propagation
--while
--no-correct-modulo
--optimize-calls
--optimize-boolify
--optimize-set!
--max-tail-depth 40
--var-elimination
--optimize-consts
- -Obench
- --tailrec
--inlining
--max-rec-inline 4
--max-inline-size 45
--inline-runtime
--constant-runtime
--propagation
--constant-propagation
--while
--no-correct-modulo
--optimize-calls
--optimize-boolify
--optimize-set!
--max-tail-depth 40
--var-elimination
--optimize-consts
--bigloo-runtime-eval
- --trampoline
- Enables trampolines. The given implementation does
not provide naive trampolines, but a more efficient version that only
returns trampolines after a constant number of tail-calls.
- --max-tail-depth depth
- Sets the maximum depth of
consecutive tail-calls before a trampoline is returned. This option is only
relevant when trampolines are enabled.
- --suspend-resume
- Enables 'suspend/resume',
a weaker (but
faster) version of 'call/cc'.
A call to 'suspend'
captures the
current continuation. 'Suspend'
does not return however, and the only
way to continue the execution is to invoke the captured continuation. The
captured continuation can only be invoked once. This form is useful, when the
program needs to pause, and wait for an event.
- --call/cc
- Enables 'call/cc'.
- --extern-invokes-call/cc
- Assume imported variables (or unresolved
variables) call 'call/cc'
(even if they do not have a 'call/cc'
entry in their 'export'-clause).
- -g
- Adds debugging information.
- -d stage
- Depending on 'stage'
either print
the expanded source, or a Scheme-version of the AST at the chosen compilation
stage (into outfile).
If you really need this, have a look at the
source for valid 'stage's.
- share/runtime.js
- The runtime stripped of
'call/cc'-related
procedures.
- share/runtime_interface.js
- Compiled programs access
the runtime through the variables declared in this file. Only needed, when
'--constant-runtime'
is not used.
- share/runtime_callcc.js
- The 'call/cc'
part of
the runtime. If a program is compiled without 'call/cc'
or
'suspend/resume'
support, then this file is not needed.
- share/runtime_interface_callcc.js
- Compiled programs
access the 'call/cc'
runtime through variables declared in this
file. Only needed, when the program has been compiled with 'call/cc'
or
'suspend/resume'
support and
'--constant-runtime'
is not activated.
Bigger programs can be split into modules. In this case the first expression
of the input-file must be a module-clause. Currently two
module-clauses are supported. An old deprecated one, and a new one that has
been modeled after Bigloo.
For the new one see Bigloo. Contrary to Bigloo the file-name and the
module-name must be the same (thus avoiding the need for an '.afile').
This limitation might be changed in future versions. In addition to the Bigloo
clauses a 'JS'
and 'scheme2js-pragma'
clause is supported. The
'JS'
clause serves to import JavaScript variables. The
'scheme2js-pragma'
to add
additional optimization information for exported variables. It
is an A-List with the variable-name used as
key. Here an example with all recognized optimization-clauses:
Explanatory example:
(module my-module ;; filename must be my-module.scm/sch
(import some-other-module
and-a-second-module)
(include "some-file"
"another-file")
(export (macro macro1) ;; a (define-macro (macro1 ..) must be in the source
(macro macro2)) ;; same here
(export (my-fun::bool arg ...) ;; a function returning a bool.
my-var) ;; export simply a variable
(scheme2js-pragma ;; optimization-information for exported variables.
(my-fun (JS "myFun") ;; use "myFun" as JS id for this variable.
(call/cc? #t) ;; this function may invoke call/cc,
(call/cc-params (0 2)))) ;; but only if arg 0 or 2 invoke call/cc.
(JS "some_JS_var")) ;; import 'some_JS_var' as 'some_JS_var'
(JS scheme-var) ;; import mangled form of 'scheme-var' as 'scheme-var'
(JS (scm-var "jsVar") ;; import 'jsVar' as 'scm-var'
(scm-var2 jsVar2))) ;; imort 'jsVar2' as 'scm-var2' (no mangling)
Here is an example for the old deprecated module-form:
(module my-module ;; filename must be my-module.scm/sch
(import some-other-module
and-a-second-module)
(include "some-file"
"another-file")
(export-macros ;; export (and use in module) macros.
(define-macro (macro-name ...) (...))) ;; same syntax as if in module-body.
(export (my-fun?
(JS js-id) ;; the JS-id
(type bool) ;; declare (return-)type of variable/function.
(constant? #t) ;; must not be changed from the outside
(call/cc? #t) ;; may invoke call/cc
(call/cc-params (0 2))) ;; but only if arg 0 or 2 invoke call/cc.
my-var ;; just export the variable without any additional information.
my-fun2) ;; works for functions too.
(JS ;; import from JavaScript (same syntax as 'export')
(time-out-set! (JS setTimeout)) ;; import setTimeout as time-out-set!
window)) ;; import window as window
The module-name must be equal to the filename (minus path and extension).
When exporting variables, only the variable-name is needed. The
'JS'
entry allows to export functions to JavaScript
under a different name, and the remaining entries help scheme2js
to optimize the
program.
When module 'foo'
is imported, then a file foo.scm or
foo.sch is searched in the include-directories (given with
-I
).
Modules without any top-level (but with a module-clause) can be used to
declare JavaScript functions and make them accessible to Scheme modules.
Infotrons are modules for JDA (http://foundry.maya.com/jda/).
When activated with '--infotron'
scheme2js
recognizes modules starting
with an 'infotron'
clause as infotrons and compiles them accordingly.
Main changes to plain modules are:
- infotrons start with 'infotron'
instead of 'module',
- they must not export any variables or macros
- they can declare 'uuid'-clauses
(or the more convenient
'uuid-seed'
string which is then used to construct a uuid),
- they can declare 'properties'
that are accepted during the initial
configuration.
- they can define the name for the initial configuration in the
'config-name'
clause. By default 'config'
is used. and
- they can declare the inputs ('iterms')
and outputs ('oterms')
- top-level must have defines at top.
Example:
(infotron jsAlert
(uuid-seed "jsAlert - Florian Loitsch - Inria")
(iterms (trigger_in on_trigger 10))
(oterms close_event_out)
(properties message))
(define (on_trigger msg)
(alert config.message)
(close_event_out msg))
Hop (http://hop.inria.fr)
JDA (http://foundry.maya.com/jda/)
R5RS (http://www.schemers.org/Documents/Standards/R5RS/)
Due to limitations in JavaScript, there are no integers (exact numbers).
At the moment scheme2js
does not support hygienic macros.
The 'eval'
function is still missing, too.
Florian Loitsch
Email: florian.loitsch@sophia.inria.fr
Version: 20110717