Commit | Line | Data |
---|---|---|
1e92094a | 1 | (in-package :js) |
8e198a08 MB |
2 | ;;;# Introduction |
3 | ;;; | |
4 | ;;; ParenScript is a simple language that looks a lot like Lisp, but | |
5 | ;;; actually is JavaScript in disguise. Actually, it is JavaScript | |
6 | ;;; embedded in a host Lisp. This way, JavaScript programs can be | |
7 | ;;; seamlessly integrated in a Lisp web application. The programmer | |
8 | ;;; doesn't have to resort to a different syntax, and JavaScript code | |
9 | ;;; can easily be generated without having to resort to complicated | |
10 | ;;; string generation or `FORMAT' expressions. | |
11 | ;;; | |
12 | ;;; An example is worth more than a thousand words. The following Lisp | |
13 | ;;; expression is a call to the ParenScript "compiler". The | |
14 | ;;; ParenScript "compiler" transforms the expression in ParenScript | |
15 | ;;; into an equivalent, human-readable expression in JavaScript. | |
16 | ||
17 | (js | |
18 | (defun foobar (a b) | |
19 | (return (+ a b)))) | |
20 | ||
21 | ;;; The resulting javascript is: | |
1e92094a | 22 | " |
8e198a08 MB |
23 | function foobar(a, b) { |
24 | return a + b; | |
25 | } | |
1e92094a | 26 | " |
8e198a08 MB |
27 | ;;; Great care has been given to the indentation and overall |
28 | ;;; readability of the generated JavaScript code. | |
29 | ||
30 | ;;;# Features | |
31 | ;;; | |
32 | ;;; ParenScript supports all the statements and expressions defined by | |
33 | ;;; the EcmaScript 262 standard. Lisp symbols are converted to | |
34 | ;;; camelcase, javascript-compliant syntax. This idea is taken from | |
35 | ;;; Linj by Antonio Menezes Leitao. Here are a few examples of Lisp | |
36 | ;;; symbol to JavaScript name conversion: | |
37 | ||
38 | (js-to-string 'foobar) => "foobar" | |
39 | (js-to-string 'foo-bar) => "fooBar" | |
40 | (js-to-string 'foo-b-@-r) => "fooBAtR" | |
41 | (js-to-string 'foo-b@r) => "fooBatr" | |
42 | (js-to-string '*array) => "Array" | |
43 | (js-to-string '*math.floor) => "Math.floor" | |
44 | ||
45 | ;;; It also supports additional iteration constructs, relieving the | |
46 | ;;; programmer of the burden of iterating over arrays. | |
47 | ;;; `for' loops can be written using the customary `DO' syntax. | |
48 | ||
49 | (js | |
50 | (do ((i 0 (incf i)) | |
51 | (j (aref arr i) (aref arr i))) | |
52 | ((>= i 10)) | |
53 | (alert (+ "i is " i " and j is " j)))) | |
54 | ||
55 | ; compiles to | |
1e92094a | 56 | " |
8e198a08 | 57 | for (var i = 0, j = arr[i]; i < 10; i = ++i, j = arr[i]) { |
1e92094a | 58 | alert('i is ' + i + ' and j is ' + j); |
8e198a08 | 59 | } |
1e92094a | 60 | " |
8e198a08 MB |
61 | ;;; ParenScript uses the Lisp reader, allowing for reader macros. It |
62 | ;;; also comes with its own macro environment, allowing host macros | |
63 | ;;; and ParenScript to coexist without interfering with each other. | |
64 | ;;; Furthermore, ParenScript uses its own compiler macro system, | |
65 | ;;; allowing for an even further customization of the generation of | |
66 | ;;; JavaScript. For example, the `1+' construct is implemented using a | |
67 | ;;; ParenScript macro: | |
68 | ||
69 | (defjsmacro 1+ (form) | |
70 | `(+ ,form 1)) | |
71 | ||
72 | ;;; ParenScript allows the creation of JavaScript objects in a Lispy | |
73 | ;;; way, using keyword arguments. | |
74 | ||
75 | (js | |
76 | (create :foo "foo" | |
77 | :bla "bla")) | |
78 | ||
79 | ; compiles to | |
1e92094a HH |
80 | " |
81 | { foo : 'foo', | |
82 | bla : 'bla' } | |
83 | " | |
8e198a08 MB |
84 | ;;; ParenScript features a HTML generator. Using the same syntax as |
85 | ;;; the `HTMLGEN' package of Franz, Inc., it can generate JavaScript | |
86 | ;;; string expressions. This allows for a clean integration of HTML in | |
87 | ;;; ParenScript code, instead of writing the tedious and error-prone | |
88 | ;;; string generation code generally found in JavaScript. | |
89 | ||
90 | (js | |
91 | (defun add-div (name href link-text) | |
92 | (document.write | |
93 | (html ((:div :id name) | |
94 | "The link is: " | |
95 | ((:a :href href) link-text)))))) | |
96 | ||
97 | ; compiles to | |
1e92094a | 98 | " |
8e198a08 | 99 | function addDiv(name, href, linkText) { |
1e92094a HH |
100 | document.write('<div id=\"' + name + '\">The link is: <a href=\"' |
101 | + href + '\">' | |
102 | + linkText + '</a></div>'); | |
8e198a08 | 103 | } |
1e92094a | 104 | " |
8e198a08 MB |
105 | ;;; In order to have a complete web application framework available in |
106 | ;;; Lisp, ParenScript also provides a sexp-based syntax for CSS | |
107 | ;;; files. Thus, a complete web application featuring HTML, CSS and | |
108 | ;;; JavaScript documents can be generated using Lisp syntax, allowing | |
109 | ;;; the programmer to use Lisp macros to factor out the redundancies | |
110 | ;;; and complexities of Web syntax. For example, to generate a CSS | |
111 | ;;; inline node in a HTML document: | |
112 | ||
113 | (html-stream *standard-output* | |
114 | (html | |
115 | (:html | |
116 | (:head | |
117 | (css (* :border "1px solid black") | |
118 | (div.bl0rg :font-family "serif") | |
119 | (("a:active" "a:hoover") :color "black" :size "200%")))))) | |
120 | ||
121 | ; which produces | |
122 | ||
123 | <html><head><style type="text/css"> | |
124 | <!-- | |
125 | * { | |
126 | border:1px solid black; | |
127 | } | |
128 | ||
129 | div.bl0rg { | |
130 | font-family:serif; | |
131 | } | |
132 | ||
133 | a:active,a:hoover { | |
134 | color:black; | |
135 | size:200%; | |
136 | } | |
137 | ||
138 | --> | |
139 | </style> | |
140 | </head> | |
141 | </html> | |
142 | ||
143 | ;;;# Getting ParenScript | |
144 | ;;; | |
145 | ;;; ParenScript can be obtained from the BKNR subversion repository at | |
146 | ||
147 | svn://bknr.net/trunk/bknr/src/js | |
148 | ||
149 | ;;; ParenScript does not depend on any part of BKNR though. You can | |
150 | ;;; download snapshots of ParenScript at the webpage | |
151 | ||
152 | http://bknr.net/parenscript | |
153 | ||
154 | ;;; or using asdf-install. | |
155 | ||
156 | (asdf-install:install 'parenscript) | |
157 | ||
158 | ;;; | |
159 | ;;; After downloading the ParenScript sourcecode, set up the ASDF | |
160 | ;;; central registry by adding a symlink to "parenscript.asd". Then | |
161 | ;;; use ASDF to load ParenScript. You may want to edit the ASDF file | |
162 | ;;; to remove the dependency on the Allegroserve HTMLGEN facility. | |
163 | ||
164 | (asdf:oos 'asdf:load-op :parenscript) | |
165 | ||
166 | ;;; ParenScript was written by Manuel Odendahl. He can be reached at | |
167 | ||
168 | manuel@bknr.net | |
169 |