File: introduction.lisp

package info (click to toggle)
parenscript 1%3A20061003-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 380 kB
  • ctags: 312
  • sloc: lisp: 2,976; python: 350; makefile: 37; sh: 36
file content (169 lines) | stat: -rw-r--r-- 5,068 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
(in-package :js)
;;;# Introduction
;;;
;;; ParenScript is a simple language that looks a lot like Lisp, but
;;; actually is JavaScript in disguise. Actually, it is JavaScript
;;; embedded in a host Lisp. This way, JavaScript programs can be
;;; seamlessly integrated in a Lisp web application. The programmer
;;; doesn't have to resort to a different syntax, and JavaScript code
;;; can easily be generated without having to resort to complicated
;;; string generation or `FORMAT' expressions.
;;;
;;; An example is worth more than a thousand words. The following Lisp
;;; expression is a call to the ParenScript "compiler". The
;;; ParenScript "compiler" transforms the expression in ParenScript
;;; into an equivalent, human-readable expression in JavaScript.

(js
  (defun foobar (a b)
    (return (+ a b))))

;;; The resulting javascript is:
"
function foobar(a, b) {
  return a + b;
}
"
;;; Great care has been given to the indentation and overall
;;; readability of the generated JavaScript code.

;;;# Features
;;;
;;; ParenScript supports all the statements and expressions defined by
;;; the EcmaScript 262 standard. Lisp symbols are converted to
;;; camelcase, javascript-compliant syntax. This idea is taken from
;;; Linj by Antonio Menezes Leitao.  Here are a few examples of Lisp
;;; symbol to JavaScript name conversion:

(js-to-string 'foobar)      => "foobar"
(js-to-string 'foo-bar)     => "fooBar"
(js-to-string 'foo-b-@-r)   => "fooBAtR"
(js-to-string 'foo-b@r)     => "fooBatr"
(js-to-string '*array)      => "Array"
(js-to-string '*math.floor) => "Math.floor"

;;; It also supports additional iteration constructs, relieving the
;;; programmer of the burden of iterating over arrays.
;;; `for' loops can be written using the customary `DO' syntax.

(js
  (do ((i 0 (incf i))
       (j (aref arr i) (aref arr i)))
      ((>= i 10))
    (alert (+ "i is " i " and j is " j))))

; compiles to
"
for (var i = 0, j = arr[i]; i < 10; i = ++i, j = arr[i]) {
  alert('i is ' + i + ' and j is ' + j);
}
"
;;; ParenScript uses the Lisp reader, allowing for reader macros. It
;;; also comes with its own macro environment, allowing host macros
;;; and ParenScript to coexist without interfering with each other.
;;; Furthermore, ParenScript uses its own compiler macro system,
;;; allowing for an even further customization of the generation of
;;; JavaScript. For example, the `1+' construct is implemented using a
;;; ParenScript macro:

(defjsmacro 1+ (form)
  `(+ ,form 1))

;;; ParenScript allows the creation of JavaScript objects in a Lispy
;;; way, using keyword arguments.

(js
  (create :foo "foo"
          :bla "bla"))

; compiles to
"
{ foo : 'foo',
  bla : 'bla' }
"
;;; ParenScript features a HTML generator. Using the same syntax as
;;; the `HTMLGEN' package of Franz, Inc., it can generate JavaScript
;;; string expressions. This allows for a clean integration of HTML in
;;; ParenScript code, instead of writing the tedious and error-prone
;;; string generation code generally found in JavaScript.

(js
  (defun add-div (name href link-text)
    (document.write
     (html ((:div :id name)
            "The link is: "
            ((:a :href href) link-text))))))

; compiles to
"
function addDiv(name, href, linkText) {
  document.write('<div id=\"' + name + '\">The link is: <a href=\"'
                                + href + '\">'
                                + linkText + '</a></div>');
}
"
;;; In order to have a complete web application framework available in
;;; Lisp, ParenScript also provides a sexp-based syntax for CSS
;;; files. Thus, a complete web application featuring HTML, CSS and
;;; JavaScript documents can be generated using Lisp syntax, allowing
;;; the programmer to use Lisp macros to factor out the redundancies
;;; and complexities of Web syntax. For example, to generate a CSS
;;; inline node in a HTML document:

(html-stream *standard-output*
  (html
   (:html
    (:head
     (css (* :border "1px solid black")
          (div.bl0rg :font-family "serif")
          (("a:active" "a:hoover") :color "black" :size "200%"))))))

; which produces

<html><head><style type="text/css">
<!--
* {
   border:1px solid black;
}

div.bl0rg {
   font-family:serif;
}

a:active,a:hoover {
   color:black;
   size:200%;
}

-->
</style>
</head>
</html>

;;;# Getting ParenScript
;;;
;;; ParenScript can be obtained from the BKNR subversion repository at

    svn://bknr.net/trunk/bknr/src/js

;;; ParenScript does not depend on any part of BKNR though. You can
;;; download snapshots of ParenScript at the webpage

    http://bknr.net/parenscript

;;; or using asdf-install.

   (asdf-install:install 'parenscript)

;;;
;;; After downloading the ParenScript sourcecode, set up the ASDF
;;; central registry by adding a symlink to "parenscript.asd". Then
;;; use ASDF to load ParenScript. You may want to edit the ASDF file
;;; to remove the dependency on the Allegroserve HTMLGEN facility.

   (asdf:oos 'asdf:load-op :parenscript)

;;; ParenScript was written by Manuel Odendahl. He can be reached at

    manuel@bknr.net