2 Javascript
The Javascript language in Mirrors allows the programatic assembly of syntactically valid Javascript. The language uses the AST structures and pretty printing libraries from Dave Herman’s javascript.plt package as its underlying representation.
Constructing Javascript fragments describes the syntax for creating blocks of Javascript and Rendering Javascript and sending Javascript responses describes how to send Javascript responses in the PLT web server.
2.1 Constructing Javascript fragments
(require (planet untyped/mirrors/javascript/syntax)) |
2.1.1 Javascript macros
Mirrors provides the following macros for creating blocks of Javascript:
Example: | ||||||||||||
| ||||||||||||
|
To prevent double-quoting errors, it is a syntax error to use the following Mirrors quote forms within a js block: xml, xml*, xml-attrs, xml-attrs*, opt-xml, opt-xml-attr, js, opt-js:
> (js (js)) |
mirrors/javascript: cannot use this identifier here |
(possible double quoting error): switch the surrounding |
quote macro to "JS" or another uppercase equivalent in: name |
You can get around this restriction using the uppercase form, JS, described below.
> (pretty-print (JS (js))) ; 'js()' function call | ||||||
|
It is a syntax error to use the following identifiers in expression position within a JS block: XML, XML*, XML-ATTRS, XML-ATTRS*, OPT-XML, OPT-XML-ATTR, JS, OPT-JS:
> (JS (JS)) |
mirrors/javascript: cannot use this identifier here |
(possible double quoting error): switch the surrounding |
quote macro to "js" or another lowercase equivalent in: name |
(if boolean-expr |
(js js-stmt ...) |
(js)) |
Examples: |
> (javascript->string (opt-js #t (alert "This statement will be printed...."))) |
"alert(\"This statement will be printed....\")" |
> (javascript->string (opt-js #f (alert "...but this statement won't."))) |
"" |
2.1.2 Javascript syntax
The forms above use the same parenthetical Javascript syntax:
js-stmt | = | js-decl | ||
| | (custom-syntax-id js-stmt ...) | |||
| | (!begin js-stmt ...) | |||
| | (!block js-stmt ...) | |||
| | (!raw string-expr) | |||
| | (!regexp str regexp-key ...) | |||
| | (if js-expr js-stmt js-stmt) | |||
| | (do js-stmt ... js-expr) | |||
| | (while js-expr js-stmt ...) | |||
| | (for (opt-decl opt-expr opt-expr) js-stmt ...) | |||
| | (for-in (decl js-expr) js-stmt ...) | |||
| | (break) | |||
| | (break id) | |||
| | (continue) | |||
| | (continue id) | |||
| | (return) | |||
| | (return js-expr) | |||
| | (with js-expr js-stmt ...) | |||
| | (switch switch-clause ...) | |||
| | (!label id js-stmt) | |||
| | (throw js-expr) | |||
| | (try try-clause ...) | |||
| | ,expr | |||
| | ,@expr | |||
| | js-expr | |||
js-decl | = | (custom-syntax-id js-decl ...) | ||
| | (function id (id ...) js-stmt ...) | |||
js-init | = | id | ||
| | [id js-expr] | |||
| | ,expr | |||
| | [id ,expr] | |||
js-expr | = | (custom-syntax-id js-expr ...) | ||
| | (js-operator js-expr ...) | |||
| | (!array js-expr ...) | |||
| | (!object [property js-expr] ...) | |||
| | (!index js-expr js-expr) | |||
| | (!dot js-expr dot-expr ...) | |||
| | (!raw string-expr) | |||
| | (!all js-expr ...) | |||
| | (? js-expr js-expr js-expr) | |||
| | (new js-expr js-expr ...) | |||
| | (function (id ...) js-stmt ...) | |||
| | ,expr | |||
| | null | |||
| | this | |||
| | id | |||
| | boolean-literal | |||
| | number-literal | |||
| | string-literal | |||
| | (quote symbol-literal) | |||
js-operator | = | ... ; Javascript operator: =, +, etc | ||
custom-syntax-id | = | id ; bound by define-js-syntax | ||
regexp-key | = | #:global? boolean-literal | ||
| | #:global? ,boolean-expr | |||
| | #:ci? boolean-literal | |||
| | #:ci? ,boolean-expr | |||
dot-expr | = | id ; property-style: a.b | ||
| | (!index id expr) ; array-style: a.b[1] | |||
| | (id js-expr ...) ; method-style: a.b(1, 2) | |||
switch-clause | = | (case id js-expr ...) | ||
| | (default js-expr ...) | |||
opt-decl | = | _ | ||
| | var-decl | |||
opt-expr | = | _ | ||
| | expr | |||
var-decl | = | (var js-init ...) |
!raw forms are treated as statements or expressions depending on their context. Semicolons and parentheses are added automatically depending on the interpretation of the block:
Examples: | ||||
; raw statements are followed by semicolons: | ||||
| ||||
| ||||
; raw expressions are surrounded by parentheses: | ||||
| ||||
alert(1 + (2) + 3) |
2.1.3 Custom Javascript syntax
(define-javascript-syntax (id arg ...) js-expr) |
(define-javascript-syntax id js-transformer) |
(define-javascript-syntax id js-transformer expr-transformer) |
The first form above behaves like define-syntax-rule. js-expr should be a regular js block.
Examples: | ||
| ||
> (javascript->string (js (!max 1 2))) | ||
"1 > 2 ? 1 : 2;" | ||
> (!max 1 2) | ||
eval:12:0: !max: must be used as a javascript expression | ||
in: (!max 1 2) |
The second and third forms behave like define-match-expander. js-transformer is a syntax transformer procedure used during Javascript expansion, which accepts a Javascript form as an input and returns a complete js block representing the expansion. expr-transformer is a transformer procedure that is used in regular Scheme expansion. When js-transformer is omitted, use of the syntax form outside of a Javascript block results in a syntax error.
Examples: | |||||||
| |||||||
> (javascript->string (js (!min 1 2))) | |||||||
"1 < 2 ? 1 : 2;" | |||||||
> (!min 1 2) | |||||||
1 |
2.2 Rendering Javascript and sending Javascript responses
2.2.1 Rendering Javascript in string form
'pretty (the default value) - javascript->string renders Javascript as well formatted blocks;
'packed - javascript->string renders Javascript on a single line, with no indentation;
'fast - javascript->string uses an experimental renderer that writes all Javascript extremely quickly onto a single line.
The 'fast rendering mode is extremely naive: it inserts extra parentheses in expressions and extra semicolons between statements. At the time of writing, it has not been properly tested: use it with caution!
Examples: | |||||
| |||||
| |||||
| |||||
| |||||
function average(a, b) { return a / 2 + b / 2; } | |||||
| |||||
functionaverage(a, b) { return ((a / 2) + (b / 2)); } |
2.2.2 Sending HTTP responses with Javascript content
| ||||||||||||||||||||||||||||||||||||||||||
code : integer = 200 | ||||||||||||||||||||||||||||||||||||||||||
message : string = "OK" | ||||||||||||||||||||||||||||||||||||||||||
seconds : integer = (current-seconds) | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
headers : (alistof symbol string) = no-cache-http-headers | ||||||||||||||||||||||||||||||||||||||||||
content : javascript-statement |