122 lines
3.7 KiB
Racket
122 lines
3.7 KiB
Racket
#lang scribble/manual
|
|
|
|
@(require (for-label racket/base js-maker))
|
|
|
|
@title{js-maker}
|
|
@author+email["Hans Dijkema" "hans@dijkewijk.nl"]
|
|
|
|
@defmodule[js-maker]
|
|
|
|
@racketmodname[js-maker] provides a deliberately small macro for generating
|
|
JavaScript text from a compact Racket/Scheme-like syntax. The public API is
|
|
intentionally limited to @racket[js]. The lower-level dispatcher used by the
|
|
implementation is internal and is not exported.
|
|
|
|
@section{Public API}
|
|
|
|
@defform[(js form ...)]{
|
|
Generates a JavaScript program fragment as a string.
|
|
|
|
Each @racket[form] is translated and emitted as a JavaScript statement. The
|
|
macro is statement-oriented. When a value must leave a generated function, use
|
|
an explicit @racket[(return expr)] form.
|
|
|
|
@codeblock{
|
|
(js
|
|
(define (add1 x)
|
|
(return (+ x 1))))
|
|
}
|
|
}
|
|
|
|
There is no public @racket[js/expression] form in js-maker 3. Expression-style
|
|
checks can be written by generating a function and using @racket[(return ...)]
|
|
inside that function.
|
|
|
|
@section{Supported forms}
|
|
|
|
The compact implementation supports:
|
|
|
|
@itemlist[
|
|
@item{@racket[(define (name arg ...) body ...)]}
|
|
@item{@racket[(define name expr)]}
|
|
@item{@racket[(lambda (arg ...) body ...)] and @racket[(λ (arg ...) body ...)]}
|
|
@item{@racket[(if condition then else)]}
|
|
@item{@racket[(begin body ...)]}
|
|
@item{@racket[(return expr)]}
|
|
@item{@racket[(set! target expr)]}
|
|
@item{ordinary @racket[let], with parallel binding semantics}
|
|
@item{@racket[let*], with sequential binding semantics}
|
|
@item{named @racket[let], compiled as a @tt{while (true)} loop}
|
|
@item{@racket[quote] and @racket[eval] for simple datum insertion}
|
|
@item{ordinary calls and the common infix operators @racket[+], @racket[-], @racket[*], @racket[/], @racket[>], @racket[<], @racket[>=], @racket[<=], @racket[==], @racket[===], @racket[!=], @racket[!==]}
|
|
@item{@racket[and], @racket[or] and @racket[not]}
|
|
@item{@racket[(send obj method arg ...)]}
|
|
@item{@racket[(new Class arg ...)]}
|
|
@item{@racket[(js-dot obj field ...)] and @racket[(dot obj field ...)]}
|
|
@item{@racket[(js-ref obj key ...)], for JavaScript bracket/index access}
|
|
@item{@racket[(list ...)] and @racket[(cons a b)]}
|
|
]
|
|
|
|
@section{Indexed access}
|
|
|
|
@racket[js-ref] is a form understood by the @racket[js] macro. It is not
|
|
exported as a separate binding. It generates JavaScript bracket access, which
|
|
works for arrays and computed object properties.
|
|
|
|
@codeblock{
|
|
(js
|
|
(define (arrayAt xs i)
|
|
(return (js-ref xs i))))
|
|
}
|
|
|
|
@codeblock{
|
|
(js
|
|
(define (nameOf obj)
|
|
(return (js-ref obj "name"))))
|
|
}
|
|
|
|
The same form can be used as a @racket[set!] target:
|
|
|
|
@codeblock{
|
|
(js
|
|
(define (put xs i value)
|
|
(set! (js-ref xs i) value)
|
|
(return xs)))
|
|
}
|
|
|
|
@section{Ordinary let}
|
|
|
|
Ordinary @racket[let] keeps Racket's parallel binding semantics. Initializers
|
|
are evaluated before the bound names are introduced. The generated JavaScript
|
|
therefore uses temporary constants and an inner block, so JavaScript's temporal
|
|
dead zone does not accidentally shadow initializer references.
|
|
|
|
@codeblock{
|
|
(js
|
|
(define (ordinaryLet x)
|
|
(let ([x 1] [y x])
|
|
(return y))))
|
|
}
|
|
|
|
@section{Named let}
|
|
|
|
Named @racket[let] is compiled to a loop. A tail call to the loop name is
|
|
translated into parallel assignments to the loop variables followed by
|
|
@tt{continue}. A branch that exits the loop should use @racket[(return ...)].
|
|
|
|
@codeblock{
|
|
(js
|
|
(define (sumTo n)
|
|
(let loop ([i 0] [acc 0])
|
|
(if (> i n)
|
|
(return acc)
|
|
(loop (+ i 1) (+ acc i))))))
|
|
}
|
|
|
|
@section{Tests and demos}
|
|
|
|
The package contains maintained tests under @filepath{testing/} and small demos
|
|
under @filepath{demo/}. The old js-maker 2 tests for runtime shims and broader
|
|
language constructs have been removed or replaced where they did not apply to
|
|
the compact js-maker 3 surface language.
|