-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathindex.html
397 lines (306 loc) · 12.3 KB
/
index.html
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
<html>
<head>
<meta charset=utf-8>
<title>Wisp playground</title>
<link rel=stylesheet href=./build/codemirror.css>
<link rel=stylesheet href=./build/solarized.css>
<script src=./build/codemirror-compressed.js></script>
<style>
html, body {
font-size: 12px;
padding: 0;
width: 100%; height: 100%; position: fixed; top: 0; left: 0; margin: 0;
}
#input, #output {
width: 50%;
float: left;
}
.CodeMirror {
height: 100%;
}
</style>
</head>
<body>
<a href="https://github.com/gozala/wisp"><img style="z-index: 3; position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub"></a>
<script type=text/expamles id=examples>;; # wisp
; Wisp is a homoiconic JS dialect with a clojure syntax, s-expressions and
; macros. Wisp code compiles to a human readable javascript, which is one
; of they key differences from clojurescript.
;; ## wisp data structures
;; 1. nil - is just like js undefined with a difference that it's
;; not something that can be defined. In fact it's just a shortcut for
;; void(0) in JS.
nil ;; => void(0)
;; 2. Booleans - Wisp booleans true / false are JS booleans
true ;; => true
;; 3. Numbers - Wisp numbers are JS numbers
1 ;; => 1
;; 4. Strings - Wisp strings are JS Strings
"Hello world"
;; Wisp strings can be multiline
"Hello,
My name is wisp!"
;; 5. Characters - Characters are sugar for JS single char strings
\a ;; => "a"
;; 6. Keywords - Keywords are symbolic identifiers that evaluate to
;; themselves.
:keyword ;; => "keyword"
;; Since in JS string constats fulfill this purpose of symbolic
;; identifiers, keywords compile to equivalent JS strings.
(window.addEventListener :load handler false)
;; Keywords can be invoked as functions, that desugars to plain
;; associated value access in JS
(:bar foo) ;; => foo["bar"]
;; 7. Vectors - Wisp vectors are JS arrays.
[ 1 2 3 4 ]
;; Note: Commas are white space & can be used if desired
[ 1, 2, 3, 4]
;; 8. Maps - Maps are hash maps, plain JS objects. Note that unlike
;; in clojure keys can not be of arbitary types.
{ "foo" bar :beep-bop "bop" 1 2 }
;; Commas are optional but can come handy for separating key value
;; pairs.
{ a 1, b 2 }
;; In a future JSONs syntax may be made compatible with map syntax.
;; 9. Lists - You can't have a lisp without lists! Wisp has lists too.
;; Wisp is homoiconic and it's code is made up of lists representing
;; expressions. The first item in the expression is a function, being
;; invoked with rest items as arguments.
(foo bar baz) ; => foo(bar, baz);
;; # Conventions
;; Wisp puts a lot of effort in making naming conventions transparent,
;; by encouraning lisp conventions and then translating them to equivalent
;; JS conventions:
(dash-delimited) ;; => dashDelimited
(predicate?) ;; => isPredicate
(**privates**) ;; => __privates__
(list->vector) ;; => listToVector
;; As a side effect some names can be expressed in a few ways, although
;; it's considered to be an advantage.
(parse-int x)
(parseInt x)
(array? x)
(isArray x)
;; # Special forms
;; There are some functions in wisp that are special, in a sence that
;; they compile to JS expressions & can not be passed around as regular
;; functions. JS operators are represteted in wisp as special forms
;; Arithmetic forms - Wisp comes with special form for arithmetic
;; operations.
(+ a b) ; => a + b
(+ a b c) ; => a + b + c
(- a b) ; => a - b
(* a b c) ; => a * b * c
(/ a b) ; => a / b
(mod a b) ; => a % 2
;; Comparison forms - Wisp comes with special forms for comparisons
(identical? a b) ;; => a === b
(= a b) ;; => a == b
(= a b c) ;; => a == b && b == c
(> a b) ;; => a > b
(>= a b) ;; => a >= b
(< a b c) ;; => a < b && b < c
(<= a b c) ;; => a <= b && b <= c
;; Logical forms - Wisp comes with special forms for logical operations
(and a b) ;; => a && b
(and a b c) ;; => a && b && c
(or a b) ;; => a || b
(and (or a b)
(and c d)) ;; (a || b) && (c && d)
;; Definitions - Variable definitions also happen through special forms.
(def a) ; => var a = void(0);
(def b 2) ; => var b = 2;
;; Assignments - In wisp new values can be set to a variables via `set!`
;; special form. Note that in functional programing binding changes are
;; a bad practice, avoiding those would make your programs only better!
;; Stil if you need it you have it.
(set! a 1)
;; Conditionals - Conditional code branching in wisp is expressed via
;; if special form. First expression following `if` is a condition,
;; if it evaluates to `true` result of the `if` expression is second
;; expression otherwise it's third expression.
(if (< number 10)
"Digit"
"Number")
;; Else expression is optional, if missing and conditional evaluates to
;; `true` result will be `nil`.
(if (monday? today) "How was your weekend")
;; Compbining expressions - In wisp is everything is an expression, but
;; sometimes one might want to compbine multiple expressions into one,
;; usually for the purpose of evaluating expressions that have
;; side-effects
(do
(console.log "Computing sum of a & b")
(+ a b))
;; Also number of expressions is `do` special form 0 to many. If `0`
;; result of evaluation will be nil.
(do)
;; Bindings - Let special form evaluates containing expressions in a
;; lexical context of in which simbols in the bindings-forms (first item)
;; are bound to their respective expression results.
(let [a 1
b (+ a c)]
(+ a b))
;; Functions - Wisp functions expressions are JS functions
(fn [x] (+ x 1))
;; Wisp functions expressions can be named similar to JS
(fn increment [x] (+ x 1))
;; Wisp functions declarations are similar, but meant to be more reused,
;; there for they have optional documentation and some metadata.
;; Note: Docstring and metadata is not presented in compiled JS yet,
;; but in a future it will compile to comments associated with function.
(defn incerement
"Returns a number one greater than given."
{:added "1.0"}
[x] (+ x 1))
;; Wisp makes capturing of rest arguments a lot easier than JS. argument
;; that follows special `&` simbol will capture all the rest args in array.
(fn [x & rest]
(rest.reduce (fn [sum x] (+ sum x)) x))
;; Overloads - In wisp functions can be overloaded depending on number
;; of arguments they take, without introspection of rest arguments.
(fn sum
([] 0)
([x] x)
([x y] (+ x y))
([x & more] (.reduce more (fn [x y] (+ x y)) x)))
;; If function does not has variadic overload and more arguments is
;; passed to it, it throws exception.
(fn
([x] x)
([x y] (- x y)))
;; ## Other Special Forms
;; Instantiation - In wisp type instantiation has a consice form, type
;; function just needs to be suffixed with `.` character
(Type. options)
;; More verbose but JS like form is also there
(new Class options)
;; Method calls - In wisp method calls are no different from function
;; calls, it's just method functions are perfixed with `.` character
(.log console "hello wisp")
;; Also more JS like forms are supported too!
(window.addEventListener "load" handler false)
;; Attribute access - In wisp attribute access is also just like function
;; call. Attribute name just needs to be prefixed with `.-`
(.-location window)
;; Compound properties can be access via `get` special form
(get templates (.-id element))
;; Catching exceptions - In wisp exceptions can be handled via `try`
;; special form. As everything else try form is also expression. It
;; results to nil if no handling takes place.
(try (raise exception))
;; Although catch form can be used to handle exceptions
(try
(raise exception)
(catch error (.log console error)))
;; Also finally clase can be used when necessary
(try
(raise exception)
(catch error (recover error))
(finally (.log console "That was a close one!")))
;; Throwing exceptions - Throw special form allows throwing exceptions,
;; although doing that is not idiomatic.
(fn raise [message] (throw (Error. message)))
;; ## Macros
;; Wisp has a programmatic macro system which allows the compiler to
;; be extended by user code. Many core constructs of Wisp are in fact
;; normal macros.
;; quote
;; Before diving into macros too much, we need to learn about few more
;; things. In lisp any expression can be marked to prevent it from being
;; evaluated. For instance, if you enter the symbol `foo` you will be
;; evaluating the reference to the value of the corresponding variable.
foo
;; If you wish to refer to the literal symbol, rather then reference you
;; could use
(quote foo)
;; or more usually
'foo
;; Any expression can be quoted, to prevent it's evaluation. Although your
;; resulting programs should not have these forms compiled to JS.
'foo
':bar
'(a b)
;; Wisp doesn’t have `unless` special form or a macro, but it's trivial
;; to implement it via macro. Although let's try implemting it as a
;; function to understand a use case for macro!
;; We want to execute body unless condition is `true`.
(defn unless-fn [condition body]
(if condition nil body))
;; Although following code will log "should not print" anyway, since
;; function arguments are exectued before function is called.
(unless-fn true (console.log "should not print"))
;; Macros solve this problem, because they do not evaluate their arguments
;; immediately. Instead, you get to choose when (and if!) the arguments
;; to a macro are evaluated. Macros take items of the expression as
;; arguments and return new form that is compiled instead.
(defmacro unless
[condition form]
(list 'if condition nil form))
;; The body of unless macro executes at macro expansion time, producing an
;; if form for compilation. Which later is compiled as usual. This way
;; compiled JS is a conditional instead of function call.
(unless true (console.log "should not print"))
;; Simple macros like above could be written via templating, expressed
;; as syntax-quoted forms.
;; `syntax-quote` is almost the same as the plain `quote`, but it allows
;; sub expressions to be unquoted so that form acts a template. Symbols
;; inside form are resolved to help prevent inadvertent symbol capture.
;; Which can be done via `unquote` and `unquote-splicing` forms.
(syntax-quote (foo (unquote bar)))
(syntax-quote (foo (unquote bar) (unquote-splicing bazs)))
;; Also there is a special syntax sugar for both unquoting operators:
;; Syntax quote: Quote form, but allow internal unquoting so that form
;; acts as template. Symbols inside form are resolved to help prevent
;; inadvertent symbol capture.
`(foo bar)
;; Unquote: Use inside a syntax-quote to substitute an unquoted value.
`(foo ~bar)
;; Splicing unquote: Use inside a syntax-quote to splice an unquoted
; list into a template.
`(foo ~bar ~@bazs)
;; For expmale build-in `defn` macro can be defined expressed with
;; simple template macro. That's more or less how build-in `defn`
;; macro is implemented.
(defmacro define-fn
[name & body]
`(def ~name (fn ~@body)))
;; Now if we use `define-fn` form above defined macro will be expanded
;; and compile time resulting into diff program output.
(define-fn print
[message]
(.log console message))
;; Not all of the macros can be expressed via templating, but all of the
;; language is available at hand to assemble macro expanded form.
;; For instance let's define macro to ease functional chanining popular
;; in JS but usually expressed via method chaining. For example following
;; API is pioneered by jQuery is very common in JS:
;;
;; open(target, "keypress).
;; filter(isEnterKey).
;; map(getInputText).
;; reduce(render)
;;
;; Unfortunately though it usually requires all the functions need to be
;; methods of dsl object, which is very limited. Making third party
;; functions second class. Via macros we can achieve similar chaining
;; without such tradeoffs.
(defmacro ->
[& operations]
(reduce
(fn [form operation]
(cons (first operation)
(cons form (rest operation))))
(first operations)
(rest operations)))
(->
(open tagret :keypress)
(filter enter-key?)
(map get-input-text)
(reduce render))
</script>
<div id=input></div>
<div id=output></div>
<script src=./build/app.js></script>
</body>
</html>