Alles aangepast.
This commit is contained in:
+66
-35
@@ -1,53 +1,84 @@
|
||||
#lang scribble/manual
|
||||
|
||||
@(require (for-label racket/base
|
||||
js-maker))
|
||||
@(require (for-label racket/base js-maker))
|
||||
|
||||
@title{js-maker}
|
||||
@author{Hans Dijkema}
|
||||
|
||||
@defmodule[js-maker]
|
||||
|
||||
@racketmodname[js-maker] provides a deliberately small syntax-driven macro for
|
||||
making JavaScript strings from a limited Racket-like surface syntax. This is a
|
||||
clean js-maker 3 restart based on the compact @filepath{js-transform.rkt}
|
||||
implementation.
|
||||
@emph{js-maker} is a deliberately small syntax-driven JavaScript string maker.
|
||||
It provides one public macro, @racket[js]. The helper machinery used to render
|
||||
subexpressions is private to the package.
|
||||
|
||||
@section{Public API}
|
||||
|
||||
@defform[(js form ...)]{
|
||||
Generates JavaScript statements for each @racket[form] and concatenates them.
|
||||
The generated JavaScript is returned as a string.
|
||||
Produces a JavaScript string for the supplied forms. Each top-level form is
|
||||
rendered as a JavaScript statement. The macro is intended for small generated
|
||||
snippets, demos, and controlled code generation; it is not a complete Racket to
|
||||
JavaScript compiler.
|
||||
|
||||
Examples:
|
||||
|
||||
@racketblock[
|
||||
(js
|
||||
(define (sum-to n)
|
||||
(let loop ([i 0] [acc 0])
|
||||
(if (> i n)
|
||||
(return acc)
|
||||
(loop (+ i 1) (+ acc i))))))]
|
||||
}
|
||||
|
||||
@defform[(js1 form)]{
|
||||
Generates JavaScript for a single expression or syntactic form and returns it as
|
||||
a string. Use this when you want the expression-level generator directly.
|
||||
|
||||
@racketblock[
|
||||
(js1 (+ 1 2))]
|
||||
(js (+ 1 2))
|
||||
(js (define answer 42))
|
||||
(js (define (square x)
|
||||
(return (* x x))))
|
||||
]
|
||||
}
|
||||
|
||||
@section{Supported core forms}
|
||||
|
||||
The compact branch supports identifiers, quoted data, primitive literals,
|
||||
function calls, infix arithmetic and comparison operators, @racket[if],
|
||||
@racket[begin], @racket[return], @racket[set!], @racket[lambda],
|
||||
@racket[define], ordinary @racket[let], @racket[let*], and named
|
||||
@racket[let].
|
||||
The compact js-maker 3 implementation supports:
|
||||
|
||||
Ordinary @racket[let] keeps Racket's parallel binding semantics. All right-hand
|
||||
sides are generated before the bound names are introduced, and the actual
|
||||
JavaScript bindings are placed in an inner block so JavaScript temporal dead zone
|
||||
rules cannot accidentally shadow the initializers.
|
||||
@itemlist[
|
||||
@item{@racket[define] for values and functions.}
|
||||
@item{@racket[lambda] and @racket[lambda]-style generated JavaScript functions.}
|
||||
@item{@racket[if], @racket[begin], @racket[set!], and explicit @racket[return].}
|
||||
@item{Ordinary @racket[let] with parallel binding semantics.}
|
||||
@item{@racket[let*] with sequential binding semantics.}
|
||||
@item{Named @racket[let] in tail-recursive loop style.}
|
||||
@item{Common infix operators such as @racket[+], @racket[-], @racket[*],
|
||||
@racket[/], comparisons, @racket[and], @racket[or], and @racket[not].}
|
||||
@item{@racket[list], @racket[cons], @racket[send], @racket[js-dot], and
|
||||
@racket[new].}
|
||||
]
|
||||
|
||||
Named @racket[let] is compiled to a JavaScript @tt{while (true)} loop. A tail
|
||||
call to the loop name is rewritten to parallel assignment of the loop variables
|
||||
followed by @tt{continue}. This keeps the important loop semantics without
|
||||
reintroducing the large js-maker 2 implementation.
|
||||
@section{Let semantics}
|
||||
|
||||
Ordinary @racket[let] evaluates all right-hand sides before introducing the new
|
||||
bindings. js-maker preserves that behavior by emitting temporary JavaScript
|
||||
constants and then opening a nested block for the real @tt{let} bindings.
|
||||
This avoids JavaScript temporal-dead-zone shadowing when a bound name is also
|
||||
used by a right-hand side.
|
||||
|
||||
@racketblock[
|
||||
(js (define (ordinary-let x)
|
||||
(let ([x 1] [y x])
|
||||
(return y))))
|
||||
]
|
||||
|
||||
The generated JavaScript returns the original argument as the value of
|
||||
@tt{y}, matching Racket's ordinary @racket[let] semantics.
|
||||
|
||||
@section{Named let}
|
||||
|
||||
Named @racket[let] is emitted as a @tt{while (true)} loop. A tail call to the
|
||||
loop name is translated to parallel update assignments followed by
|
||||
@tt{continue}. The intended style is statement-oriented and uses explicit
|
||||
@racket[return] for terminating branches.
|
||||
|
||||
@racketblock[
|
||||
(js (define (sum-to n)
|
||||
(let loop ([i 0] [acc 0])
|
||||
(if (> i n)
|
||||
(return acc)
|
||||
(loop (+ i 1) (+ acc i))))))
|
||||
]
|
||||
|
||||
@section{Package layout}
|
||||
|
||||
The package includes small demos under @filepath{demo/} and a regression suite
|
||||
under @filepath{testing/}. The public API remains just @racket[js].
|
||||
|
||||
Reference in New Issue
Block a user