source: project/wiki/eggref/5/spock @ 37476

Last change on this file since 37476 was 37476, checked in by felix winkelmann, 19 months ago

added spock eggref page

File size: 27.9 KB
Line 
1[[tags:eggs]]
2
3<nowiki>
4<center><img style="margin-top:3em;" src="http://www.call-with-current-continuation.org/star-trek-spock1.jpg"/>
5</center>
6</nowiki>
7
8[[toc:]]
9
10
11== spock
12
13=== Introduction
14
15SPOCK is a compiler and runtime system for translating most of R5RS
16Scheme into JavaScript.  You can use it either by statically
17generating JavaScript files from Scheme source files or by translating
18s-expressions containing Scheme code on the fly. The compiler uses
19Henry Baker's
20[[http://home.pipeline.com/~hbaker1/CheneyMTA.html|Cheney-on-the-MTA]]
21compilation strategy.
22
23This extension is still in a very early state and is likely to contain
24numerous bugs. There are known problems with Internet Explorer and the
25system has only been tested on a few browsers. Moreover, the
26compilation strategy used stresses JavaScript implementations in
27unusual ways and the results indicate that many JavaScript engines
28seem to have quite serious limitations regarding static function
29nesting and closure performance.
30
31Note: Spock requires CHICKEN 5.0.1 or later.
32
33=== Programming interface
34
35==== State management
36
37Compilation of Scheme to JavaScript is controlled by a ''state''
38object that specifies options relevant to the translation process
39together with a syntactic ''environment'', i.e. the macro-definitions
40available to the code to be compiled. Depending on the use of the
41compiler, it must be possible to explicitly create a new state or
42re-use an existing one. For example, in a web-server, one usually
43needs a state local to the current request - syntactic definitions and
44compilation options should not necessarily be shared between multiple
45requests.
46
47===== Compilation options
48
49Compilation options are given as a list of symbols, where some
50symbols must be followed by an argument:
51
52<table>
53<tr><th>Option</th><th>Argument</th><th>Meaning</th></tr>
54<tr><td>source</td><td></td>              <td>show source forms</td></tr>
55<tr><td>expand</td><td></td>              <td>show forms after macro-expansion</td></tr>
56<tr><td>canonicalized</td><td></td>       <td>show forms after canonicalization</td></tr>
57<tr><td>optimized</td><td></td>           <td>show forms after optimization</td></tr>
58<tr><td>cps</td><td></td>                 <td>show forms after CPS-conversion</td></tr>
59<tr><td>strict</td><td></td>              <td>enable strict mode</td></tr>
60<tr><td>optimize</td><td></td>            <td>enable optimizations</td></tr>
61<tr><td>block</td><td></td>               <td>enable block-compilation</td></tr>
62<tr><td>library-path</td><td>[DIR]</td>   <td>add DIR to library path or return library path</td></tr>
63<tr><td>namespace</td><td> VAR</td>       <td>put globals into module</td></tr>
64<tr><td>xref</td><td></td>                <td>show cross-reference</td></tr>
65<tr><td>runtime</td><td></td>             <td>include runtime-system in generated code</td></tr>
66<tr><td>library</td><td></td>             <td>compile runtime library</td></tr>
67<tr><td>seal</td><td></td>                <td>wrap toplevel definitions into local scope</td></tr>
68<tr><td>debug</td><td></td>               <td>enable debug-mode</td></tr>
69<tr><td>usage</td><td>PROC</td>          <td>invoke PROC on usage-errors</td></tr>
70<tr><td>fail</td><td>PROC</td>           <td>invoke PROC on compiler-errors</td></tr>
71<tr><td>import</td><td> FILENAME</td>     <td>expand FILENAME</td></tr>
72<tr><td>environment</td><td> STORE</td>   <td>provide syntactic environment</td></tr>
73<tr><td>debug-syntax</td><td></td>        <td>show debug-output during expansion</td></tr>
74<tr><td>verbose</td><td></td>             <td>show diagnostic messages</td></tr>
75<tr><td>prepare</td><td></td>             <td>just prepare state without compiling</td></tr>
76<tr><td>code</td><td>EXP</td>            <td>code to be compiled instead of file</td></tr>
77<tr><td>output-file </td><td>FILENAME</td>   <td>specify output-file</td></tr>
78</table>
79
80Note that the argument to the {{library-path}} option may be omitted,
81which means it must be the last element in the option list.
82
83===== make-spock-state
84
85<procedure>(make-spock-state OPTION ...)</procedure>
86
87Creates a fresh compilation state, with settings given in {{OPTION ..}}
88and returns this state.
89
90===== spock-state?
91
92<procedure>(spock-state? X)</procedure>
93
94Returns {{#t}} if {{X}} is a compilaton state or {{#f}} otherwise.
95
96===== current-spock-state
97
98<parameter>current-spock-state</parameter>
99
100The currently active compilation state. Defaults to {{#f}},
101which means a new state will be created automatically for
102the next compilation (via {{<spock>}}) and will be re-used
103on subsequent compilations.
104
105===== spock
106
107<procedure>(spock FILENAME-OR-OPTION ...)</procedure>
108
109The main interface to the compiler. Any string-argument given will be
110taken as the name of a Scheme source file to be compiled. If the
111{{code}} option is given and followed by an expression, then that
112expression is compiled instead of reading source from files.
113The other options are the same as those that can be passed to
114{{make-spock-state}}.
115
116===== spock-initialize
117
118<procedure>(spock-initialize OPTIONS ...)</procedure>
119
120Creates a compilation state using the given options and sets the value
121of the parameter {{current-spock-state}}.  Initialization of a
122compilation state needs a bit of internal setup, so it is advisable to
123call this procedure in time-critical applications that need to
124generate code quickly.
125
126===== <spock>
127
128<syntax>(<spock> FORM)</syntax>
129
130Compiles the Scheme (unquoted) expression {{FORM}} using the current
131compilation state and returns the generated JavaScript code as a
132string. {{FORM}} may contain sub-expressions of the form
133{{(<unscript>}} and {{<unscript-splicing>}}, respectively, which work
134similar to {{unquote}} and {{unquote-splicing}} in R5RS Scheme, but
135switch between code to be compiled and code or literal data to be
136computed in the host environment, e.g.
137
138  (<spock>
139    (begin
140      (define (square x) (* x x))
141      (print (square '(<unscript> (read))))))
142
143will return a {{<script>}} HTML element containing JavaScript code
144that defines a function and calls it with the argument read at
145execution of the {{<spock>}} expression.
146
147Note that the compiled form needs runtime support code to
148execute successfully. See {{<spock-header>}} below.
149
150===== <spock-header>
151
152<procedure>(<spock-header> #!key minified debug path)</procedure>
153
154Emits HTML to load the runtime system. Keyword-arguments are available
155to specify whether a "minified" version of the runtime library should
156be loaded, and whether a debug version should be used. Minified means
157a compressed library that can be loaded faster by the client. The
158debug version performs additional error checks and keeps a trace of
159recently invoked functions.
160
161Note that the JavaScript files containing the runtime library need to
162be available to be transmitted to the client. In the usual case of
163web-server code generating script content this means, one of the files
164
165  spock-runtime.js
166  spock-runtime-min.js
167  spock-runtime-debug.js
168  spock-runtime-debug-min.js
169
170should be in a location that holds files to be retrieved by the client
171and it should match the keyword arguments given to
172{{<spock-header>}}. The {{path}} keyword argument can be used to
173override the path prefix and defaults to an empty path.
174
175The runtime library is installed in {{spock}} subdirectory of the
176extension repository and can be located in the path returned by
177entering
178
179  chicken-spock -library-path
180
181==== Special read syntax
182
183To make embedding of Scheme code fragments easier, read syntax
184is available that simplifies the use of the {{<spock>}}:
185
186  #`EXPRESSION   --->   (<spock> EXPRESSION)
187  #^EXPRESSION   --->   (<unscript> EXPRESSION)
188  #^@EXPRESSION  --->   (<unscript-splicing> EXPRESSION)
189
190In compiled code, you must explicitly load the {{spock}} extension to
191make the read-syntax available by passing {{-X spock}} to the compiler
192and the {{spock}} module must be imported.
193
194=== Using the static compiler
195
196The compiler takes one or more Scheme files are translates them
197into a single JavaScript file, writing it by default to stdout. You
198can use the {{-o}} option to specify a file into which the code
199should be written instead. The compiler understands most of the
200options that can be given to {{make-spock-state}}, enter
201
202  chicken-spock -help
203
204for a list of command-line switches.
205
206=== Supported language
207
208==== Deviations from R5RS
209
210; 4.1.1 : Access to unbound variables will trigger whatever error-handling the underlying JavScript implementation provides.
211
212; 6.1 : {{eq?}} will return {{#f}} when given standard procedures, since these are mostly implemented by using so called "identifier syntax" - in other words
213
214  (eq? car car)      ===>  #f
215
216; 6.2.2 : there is no concept of ''exactness'' in JavaScript - all numbers are internally represented as floating-point numbers and are thus inexact; "bignums", exact rational numbers and complex numbers are not supported.
217
218; 6.2.5 : the following standard procedures are not implemented: {{denominator}}, {{numerator}}, {{image-part}}, {{real-part}}, {{rationalize}}, {{make-polar}} and {{make-rectangular}}. {{inexact->exact}} merely rounds its argument, {{exact->inexact}} returns its argument unchanged.
219
220; 6.3.5 : non-integral string indices are not checked and return undefined result.
221
222; 6.3.6 : non-integral vector indices are not checked and return undefined result.
223
224; 6.4 : continuations captured over the program toplevel can not be re-entered, so
225
226  (define k (call-with-current-continuation (lambda (k) k)))
227  (display "once\n")
228  (k #f)
229
230will not print {{once}} a second time and will simply return at the next toplevel expression.
231
232; 6.5 : {{eval}} is not supported.
233
234; 6.6.4 : {{load}} can only load JavaScript code and always does so asynchronously; {{transcript-on}} and {{transcript-off}} are not supported.
235
236==== Extensions to R5RS
237
238; 4.1.1 : SPOCK provides a special notation to simplify access to object properties, similar to the ''dot notation'' supported by several Java- and JavaScript-based Scheme implementations:
239
240  .NAME            ==>   (%property-ref "NAME")
241  .NAME1.NAME2     ==>   (%property-ref "NAME1.NAME2")
242  NAME1.NAME2      ==>   (%host-ref "NAME1.NAME2")
243  NAME.            ==>   (%host-ref "NAME")
244
245  (set! NAME1.NAME2 X)   ==>   (%host-set! "NAME1.NAME2" X)
246  (set! NAME1. X)        ==>   (%host-set! "NAME1" X)
247  (set! (.NAME X) Y)     ==>   (%property-set! "NAME" X Y)
248  (set! (.NAME1.NAME2 X) Y)     ==>   (%property-set! "NAME1.NAME2" X Y)
249
250; 6.3.5 : the second argument to {{substring}} is optional and defaults to the length of the argument string; {{string-fill!}} accepts an optional third and fourth argument specifying the start end end index of the region whould should be filled.
251
252; 6.3.6 : {{vector-fill!}} accepts an optional third and fourth argument specifying the start end end index of the region whould should be filled.
253
254; 6.4 : {{for-each}} and {{map}} accept a vector as their second argument, but only when called with two arguments; {{apply}} accepts a vector as last argument.
255
256; 6.6.4 : {{load}} takes an optional second argument, which should be a procedure of one argument; this procedure will be called with the filename argument when the file could be successfully loaded; the filename is actually an URL.
257
258==== Non-standard syntax
259
260SPOCK uses ''alexpander'', a R5RS {{syntax-rules}} implementation by Al Petrofsky.
261This macro package provides numerous extensions which are currently not documented
262here.
263
264Additionally, the following non-standard syntax is available:
265
266===== begin1
267
268<syntax>(begin1 X1 X2 ...)</syntax>
269
270Evaluates the forms and returns the result(s) of the first one.
271
272===== fluid-let
273
274<syntax>(fluid-let ((ID1 X1) ...) BODY ...)</syntax>
275
276Dynamically binds the variables {{ID1 ...}} during the execution of {{BODY}}.
277
278===== when
279===== unless
280
281<syntax>(when X1 BODY ...)</syntax>
282<syntax>(unless X1 BODY ...)</syntax>
283
284Conditionals with the usual meaning.
285
286===== cut
287
288<syntax>(cut ...)</syntax>
289
290[[http://srfi.schemers.org/srfi-26/srfi-26.html|Syntactic sugar for specializing parameters]].
291
292===== cond-expand
293
294<syntax>(cond-expand CLAUSE ...)</syntax>
295
296[[http://srfi.schemers.org/srfi-0/srfi-0.html|Feature-based conditional expansion]].
297
298===== define-syntax-rule
299
300<syntax>(define-syntax-rule (NAME ARG ...) BODY)</syntax>
301
302Equivalent to
303
304<enscript highlight=scheme>
305(define-syntax NAME
306  (syntax-rules ()
307    ((_ ARG ...) BODY)))
308</enscript>
309
310===== new
311
312<syntax>(new CLASS KEY1 VALUE1 ...)</syntax>
313
314Creates a JavaScript object that has the constructor {{CLASS}}, which
315must be a native JavaScript function. The arguments should be a list of
316alternating keys (native strings) and values.
317
318===== define-native
319
320<syntax>(define-native NAME ...)</syntax>
321
322Declares {{NAME}} to be a native JavaScript function.
323
324===== define-native-method
325
326<syntax>(define-native-method NAME ...)</syntax>
327
328Declares {{NAME}} to be a native JavaScript method, which takes
329an additional initial argument (the "this" object).
330
331===== define-entry-point
332
333<syntax>(define-entry-point NAME EXP)</syntax>
334<syntax>(define-entry-point (NAME . LLIST) BODY ...)</syntax>
335
336Declares {{NAME}} to be a global JavaScript variable which will
337execute {{BODY}} when called from native code.
338
339==== Non-standard library procedures
340
341===== %
342
343<procedure>(% STRING1 VALUE1 ...)</procedure>
344
345Creates an anonymous JavaScript object from the keys and values given by
346{{STRING1 VALUES1 ...}}.
347
348===== bind-method
349
350<procedure>(bind-method JSFUNC OBJECT)</procedure>
351
352Returns a procedure that will invoke the native JavaScript function {{JSFUNC}}
353with {{OBJECT}} as the implicit "this" parameter.
354
355===== callback
356
357<procedure>(callback PROC)</procedure>
358
359Returns a native JavaScript function that, when invoked, will call the
360Scheme procedure {{PROC}}.
361
362===== callback-method
363
364<procedure>(callback-method PROC)</procedure>
365
366Returns a native JavaScript function that, when invoked as a method,
367will pass the implicit "this" parameter as an additional first argument
368to the Scheme procedure {{PROC}}.
369
370===== compl
371
372<procedure>(compl PROC)</procedure>
373
374Equivalent to {{(lambda (x) (not (PROC x)))}}.
375
376===== const
377
378<procedure>(const X)</procedure>
379
380Equivalent to {{(lambda _ (X))}}.
381
382===== current-error-port
383
384<procedure>(current-error-port)</procedure>
385
386Returns the port that will receive error output. The exact behaviour
387depends on the host environment.
388
389===== exit
390
391<procedure>(exit [CODE])</procedure>
392
393Exits the JavaScript interpreter (not functional inside the browser).
394
395===== file-exists?
396
397<procedure>(file-exists? STRING)</procedure>
398
399Returns {{#t}} if a file with the given name exists (not functional inside the
400browser).
401
402===== id
403
404<procedure>(id X)</procedure>
405
406Returns {{X}}.
407
408===== jstring
409
410<procedure>(jstring X)</procedure>
411
412If {{X}} is a mutable string, returns a native JavaScript string. Any other
413argument is returned unchanged.
414
415===== milliseconds
416
417<procedure>(milliseconds [THUNK])</procedure>
418
419Returns the current time in milliseconds.
420
421===== native
422
423<procedure>(native JSFUNC)</procedure>
424
425Returns a procedure that, when called, will invoke the native JavaScript function
426{{JSFUNC}}.
427
428===== native-method
429
430<procedure>(native-method JSFUNC)</procedure>
431
432Returns a procedure that, when called, will pass the first argument as the
433implicit "this" parameter to {{JSFUNC}}.
434
435===== o
436
437<procedure>(o PROC ...)</procedure>
438
439Function-composition.
440
441===== print
442
443<procedure>(print X ...)</procedure>
444
445Prints its argument to the current output port. Depends on the host environment.
446
447===== void
448
449<procedure>(void ...)</procedure>
450
451Ignores its arguments and returns the undefined value.
452
453===== void?
454
455<procedure>(void? X)</procedure>
456
457Returns {{#t}} if {{X}} is the undefined value.
458
459===== with-input-from-port
460===== with-output-to-port
461
462<procedure>(with-input-from-port PORT THUNK)</procedure>
463<procedure>(with-output-to-port PORT THUNK)</procedure>
464
465Invoke the zero-argument procedure {{THUNK}} with the current
466input or output port changed to {{PORT}}.
467
468==== Internal special forms
469
470===== %code
471
472<syntax>(%code STRING ...)</syntax>
473
474Embeds JavaScript code directly.
475
476===== %host-ref
477===== %host-set!
478
479<syntax>(%host-ref NAME ...)</syntax>
480<syntax>(%host-set! NAME X)</syntax>
481
482Retrieves a JavaScript variable or assigns a new value to it. Note that no
483automatic value conversion takes place, in particular, strings should be
484converted to the native representation when assigned.
485
486===== %inline
487
488<syntax>(%inline .NAME THIS X ...)</syntax>
489<syntax>(%inline NAME X ...)</syntax>
490
491Embeds code for an inline JavaScript operation. The first form invokes
492the method {{NAME}} on the object {{THIS}}. The second invokes a normal
493JavaScript function.
494
495===== %native-lambda
496
497<syntax>(%native-lambda STRING ...)</syntax>
498
499Returns a procedure containing native JavaScript code. Use
500{{arguments}} to refer to the function arguments. The implicit
501variable {{K}} holds the continuation and should be invoked with the
502result value(s) on return.
503
504===== %new
505
506<syntax>(%new CLASS X ...)</syntax>
507
508Invokes the object constructor {{CLASS}} (which should be a string or symbol)
509with the given arguments and returns the object.
510
511===== %property-ref
512===== %property-set!
513
514<syntax>(%property-ref NAME [X])</syntax>
515<syntax>(%property-set! NAME X Y)</syntax>
516
517Retrieve or set the named property {{NAME}} (a string or symbol) of object {{X}}.
518The second form assigns {{Y}} to the property {{NAME}} of {{X}}. No automatic
519argument conversions take place.
520
521{{(%property-ref NAME)}} is a shortcut for {{(lambda (x) (%property-ref NAME))}}.
522
523==== How Scheme types map to JavaScript types
524
525<table>
526<tr><th>Scheme</th><th>JavaScript</th></tr>
527<tr><td>number</td><td>number</td></tr>
528<tr><td>character</td><td>[Object SPOCK.Char]</td></tr>
529<tr><td>eof-object</td><td>[Object SPOCK.EndOfFile] == SPOCK.EOF</td></tr>
530<tr><td>string</td><td>string or [Object SPOCK.String]</td></tr>
531<tr><td>symbol</td><td>[Object SPOCK.Symbol]</td></tr>
532<tr><td>port</td><td>[Object SPOCK.Port]</td></tr>
533<tr><td>boolean</td><td>boolean</td></tr>
534<tr><td>pair</td><td>[Object SPOCK.Pair]</td></tr>
535<tr><td>vector</td><td>Array</td></tr>
536<tr><td>null</td><td>null</td></tr>
537<tr><td>void</td><td>undefined</td></tr>
538</table>
539
540Scheme code can handle native JavaScript strings, which are
541immutable. String literals will be directly represented as native
542JavaScript strings. Mutable strings (as returned by {{make-string}},
543for example) will be instances of {{SPOCK.String}} and must be
544manually converted to JavaScript strings when passed to JavaScript
545code.
546
547==== Notes
548
549* Argument counts are not checked. If a procedure is called with fewer arguments, the formal variables corresponding to the omitted arguments are initialized to the ''void'' value (as returned by the {{void}} procedure); surplus arguments are ignored.
550
551=== Examples
552
553==== Using dynamic code generation
554
555<enscript highlight=scheme>
556(use spock)
557
558(display (<spock-header> debug: #t))
559
560(display #`(print #^(+ 3 4)))
561</enscript>
562
563produces:
564
565<enscript highlight=html>
566<script type='text/javascript' src='spock-runtime-debug-min.js'></script>
567</enscript>
568
569and:
570
571<enscript highlight=html>
572<script type='text/javascript'>
573/* CODE GENERATED BY SPOCK 0 */
574var t2 = function (k1) {
575 return ___print(k1, 7);
576};
577SPOCK.run(t2);
578SPOCK.flush();
579/* END OF GENERATED CODE */
580</script>
581</enscript>
582
583
584==== Using the static compiler
585
586<enscript highlight=html>
587<!-- drag.html - drag a box around the screen -->
588
589<html>
590  <head>
591    <script src="spock-runtime-debug.js"></script>
592    <script src="drag.js"></script>
593    <style type="text/css">
594      body {
595        font-family: Arial, Helvetica;
596        font-size: x-large;
597      }
598
599      #info {
600        position: absolute;
601        right-margin: auto;
602        left: 0px;
603        top-margin; auto;
604        bottom: 0px;
605      }
606
607      #box {
608        width: 200px;
609        height: 200px;
610        background-color: red;
611        position: absolute;
612        left: 50%;
613        top: 50%;
614      }
615    </style>
616  </head>
617  <body>
618    <div id="info">xxx</div>
619    <div id="box">Push me.</div>
620  </body>
621</html>
622</enscript>
623
624<enscript highlight=scheme>
625;;;; drag.scm
626
627(define (box) (%inline "document.getElementById" "box"))
628(define (info) (%inline "document.getElementById" "info"))
629
630(define (mouse-position event)
631  (values
632   (- (+ (.clientX event) document.body.scrollLeft) document.body.clientLeft)
633   (- (+ (.clientY event) document.body.scrollTop) document.body.clientTop)))
634
635(define (mouse-move event)
636  (call-with-values (cut mouse-position event)
637    (lambda (x y)
638      (move-element (box) x y)
639      (show-position x y))))
640
641(define (move-element elt x y)
642  (set! (.style.left elt) x)
643  (set! (.style.top elt) y))
644
645(define (move-element-by elt x y)
646  (call-with-values (cut element-position elt)
647    (lambda (x1 y1)
648      (move-element elt (+ x1 x) (+ y1 y)))))
649
650(define (element-position elt)
651  (values
652   (.offsetLeft elt)
653   (.offsetTop elt)))
654
655(define (show-position x y)
656  (set! (.innerHTML (info))
657    (jstring
658     (string-append
659      (number->string x) "/" (number->string y)))))
660
661(set! document.onmousemove (callback mouse-move))
662</enscript>
663
664To compile this, enter:
665
666  chicken-spock drag.scm -o drag.js
667
668Now copy {{spock-runtime.js}} from the repository into the same
669directory holding {{drag.js}} and {{drag.html}} and open {{drag.html}}
670in your browser.
671
672==== Using continuations for cooperative multitasking
673
674<enscript highlight=scheme>
675;; http://www.pixelwit.com/blog/2008/04/how-to-draw-a-spiral/
676
677;; centerX-- X origin of the spiral.
678;; centerY-- Y origin of the spiral.
679;; radius--- Distance from origin to outer arm.
680;; sides---- Number of points or sides along the spiral's arm.
681;; coils---- Number of coils or full rotations. (Positive numbers spin clockwise, negative numbers spin counter-clockwise)
682;; rotation- Overall rotation of the spiral. ('0'=no rotation, '1'=360 degrees, '180/360'=180 degrees)
683     
684(define (spiral ctx center-x center-y radius sides coils rotation)
685  (let* ((away-step (/ radius sides))
686         (around-step (/ coils sides))
687         (around-radians (* around-step 2 Math.PI))
688         (rotation (* rotation 2 Math.PI)))
689    (let loop ((i 0) (px center-x) (py center-y))
690      (yield)
691      (cond ((<= i sides)
692             (%inline ".beginPath" ctx)
693             (%inline ".moveTo" ctx px py)
694             (let* ((away (* i away-step))
695                    (around (+ (* i around-radians) rotation))
696                    (x (+ center-x (* (%inline "Math.cos" around) away)))
697                    (y (+ center-y (* (%inline "Math.sin" around) away))))
698               (%inline ".lineTo" ctx x y)
699               (%inline ".stroke" ctx)
700               (loop (+ i 1) x y)))
701            (else
702             (%inline
703              ".fillRect" ctx
704              (- center-x radius 10) (- center-y radius 10)
705              (+ 20 (* radius 2)) (+ 20 (* radius 2)))
706             (loop 0 center-x center-y))))))
707
708(define canvas (%inline "document.getElementById" "canvas"))
709(define ctx (%inline ".getContext" canvas "2d"))
710
711(set! (.lineWidth ctx) 5)
712(set! (.lineStyle ctx) "rgb(0, 0, 255)")
713(set! (.fillStyle ctx) "rgb(255, 200, 255)")
714
715(%inline ".fillRect" ctx 0 0 600 600)
716
717(define halt #f)
718(define threads '())
719
720(let* ((n 4)
721       (wh (/ 600 n)))
722  (do ((x 1 (+ x 1)))
723      ((> x n))
724    (let ((cx (- (* wh x) (/ wh 2))))
725      (do ((y 1 (+ y 1)))
726          ((> y n))
727        (let ((cy (- (* wh y) (/ wh 2))))
728          (set! threads
729            (cons
730             (lambda ()
731               ;;(%inline "console.log" cx cy)
732               (spiral ctx cx cy (/ wh 2) 200 4 (%inline "Math.random")))
733             threads)))))))
734
735(define current threads)
736
737(define (yield)
738  (call-with-current-continuation
739   (lambda (k)
740     (set-car! current (lambda () (k #f)))
741     (set! current (cdr current))
742     (when (null? current) (set! current threads))
743     (%inline "setTimeout" (callback (lambda () ((car current)))) 1)
744     (halt))))
745
746(call-with-current-continuation
747 (lambda (k)
748   (set! halt (lambda () (k #f)))
749   ((car threads))))
750</enscript>
751
752<enscript highlight=html>
753<html>
754  <head>
755    <style>
756      canvas#canvas {
757        position: absolute;
758        left: 100px;
759        top: 50px;
760        width: 600px;
761        height: 600px;
762      }
763    </style>
764  </head>
765  <body>
766    <canvas id="canvas" width="600" height="600"></canvas>
767    <script src="../spock/spock-runtime-min.js"></script>
768    <script src="threads.js"></script>
769  </body>
770</html>
771</enscript>
772
773See it in action here (needs browser with {{<canvas>}} support):
774
775[[http://www.call-with-current-continuation.org/spock/threads.html]]
776
777
778=== Authors
779
780[[/users/felix winkelmann|felix winkelmann]]
781
782=== License
783
784 Copyright (c) 2011-2019, Felix L. Winkelmann
785 All rights reserved.
786
787 Redistribution and use in source and binary forms, with or without
788 modification, are permitted provided that the following conditions
789 are met:
790 
791   Redistributions of source code must retain the above copyright
792   notice, this list of conditions and the following disclaimer.
793 
794   Redistributions in binary form must reproduce the above copyright
795   notice, this list of conditions and the following disclaimer in the
796   documentation and/or other materials provided with the
797   distribution.
798 
799   Neither the name of the author nor the names of its contributors
800   may be used to endorse or promote products derived from this
801   software without specific prior written permission.
802 
803 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
804 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
805 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
806 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
807 HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
808 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
809 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
810 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
811 AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
812 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
813 WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
814 POSSIBILITY OF SUCH DAMAGE.
815 
816 The pattern matching library used by SPOCK is derived from code is
817 written by Alex Shinn and placed in the Public Domain.
818 
819 The pretty printer used internally is Copyright (c) 1991, Marc Feeley
820 (feeley@iro.umontreal.ca), Distribution restrictions: none
821 
822 The syntax-rules expander used is ''alexpander'', Copyright 2002-2004
823 Al Petrofsky <alexpander@petrofsky.org>
824 
825 Redistribution and use in source and binary forms, with or without
826 modification, are permitted provided that the following conditions
827 are met:
828 
829 Redistributions of source code must retain the above copyright
830 notice, this list of conditions and the following disclaimer.
831 
832 Redistributions in binary form must reproduce the above copyright
833 notice, this list of conditions and the following disclaimer in the
834 documentation and/or other materials provided with the distribution.
835 
836 Neither the name of the author nor the names of its contributors may
837 be used to endorse or promote products derived from this software
838 without specific prior written permission.
839 
840 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
841 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
842 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
843 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
844 HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
845 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
846 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
847 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
848 AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
849 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
850 WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
851 POSSIBILITY OF SUCH DAMAGE.
852
853=== Version History
854
855; 0.1 : port to CHICKEN 5
856; 0.097 : fix in {{SPOCK.stringify}} for non-proper lists, contributed by Hugo Arregui
857; 0.096 : fixed implementation of {{cadXXr}}, thanks to Hugo Arregui
858; 0.095 : fixed CPS-conversion of conditionals; use correct logging port on node.js and handle sign-character in string->number conversion (thanks to Alexander Shendi)
859; 0.05 : runtime code uses "SPOCK.global" instead of "this"
860; 0.04 : fixed incorrect version number in setup script (reported by Mario Domenech Goulart)
861; 0.03 : renamed {{<script>}} to {{<spock>}}, fixed bug in {{spock}} driver procedure (Thanks to Mario Domenech Goulart)
862; 0.02 : metafile fix reported by mario
863; 0.01 : initial release
Note: See TracBrowser for help on using the repository browser.