#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.