8 | <@ jwacs_imports @>
9 |
10 |
11 |
--------------------------------------------------------------------------------
/reference/README:
--------------------------------------------------------------------------------
1 | This directory holds useful code or documents that can be used for reference.
2 |
3 | ecmscript.grammar - a Yacc-compatable grammar for ECMAScript R3
4 | ecmascript.g - a SableCC grammar for ECMAScript R3
5 |
6 | tramp-perf.js - some simple factorial-based benchmarks for various transformations of factorial
--------------------------------------------------------------------------------
/package.lisp:
--------------------------------------------------------------------------------
1 | ;;;; package.lisp
2 | ;;;
3 | ;;; Define the packages used by the jwacs system.
4 | ;;;
5 | ;;; Copyright (c) 2005 James Wright
6 | ;;; See LICENSE for full licensing details.
7 |
8 | ;; Eventually this may want to be several sub-packages, but let's start simple for now
9 | (defpackage :jwacs
10 | (:use :cl :cl-ppcre)
11 | (:nicknames :jw)
12 | (:export
13 | #:parse
14 | #:process #:build-app
15 | #:syntax-error #:missing-import
16 | #:main))
17 |
--------------------------------------------------------------------------------
/examples/build-examples:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | if [ -x ../bin/jwacs ] ; then
4 |
5 | ../bin/jwacs --noinform -p /lib/=../lib CalendarMark2.jw
6 | ../bin/jwacs --noinform Counter.jw
7 | ../bin/jwacs --noinform TrivialHttpRequest.jw
8 |
9 | else
10 |
11 | echo Cannot find jwacs binary!
12 | echo You can build the examples by evaluating
13 | echo " (asdf:oos 'asdf:load-op :jwacs-tests)"
14 | echo " (jw-tests::compile-examples)"
15 | echo from the REPL.
16 |
17 | fi
--------------------------------------------------------------------------------
/examples/Counter.template:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Counter example
5 |
13 |
14 |
15 |
Loading...
16 | <@ jwacs_imports @>
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | jwacs - Javascript With Advanced Continuation Support
2 |
3 | Jwacs is a program for transforming code written in an extended version of
4 | Javascript that contains continuation support into regular Javascript that can
5 | be run in any standards-compliant browser.
6 |
7 | The extended language is also called jwacs, which is perhaps a little confusing.
8 | Suggestions are welcome.
9 |
10 | See doc/index.html or http://chumsley.org/jwacs/ for documentation, including a Quick
11 | Start guide.
12 |
--------------------------------------------------------------------------------
/examples/CalendarMark2.template:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Calendar
5 |
6 |
7 |
8 |
Loading...
9 |
10 | <@ jwacs_imports @>
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/WebIdeClient.css:
--------------------------------------------------------------------------------
1 | .exception
2 | {
3 | background: orange;
4 | }
5 |
6 | .frame
7 | {
8 | margin-top: 12pt;
9 | margin-bottom: 12pt;
10 | width:650px;
11 | }
12 |
13 | #sourceText, #dummyDiv
14 | {
15 | font-family: Courier, sans-serif;
16 | font-size: 12px;
17 | padding: 0px 0px 0px 0px;
18 | margin:0px 0px 0px 0px;
19 | }
20 |
21 | #dummyDiv
22 | {
23 | visibility: hidden;
24 | position: absolute;
25 | top: -100px;
26 | left: -100px;
27 | }
28 |
29 | #contentDiv
30 | {
31 | width: 80%;
32 | margin: 0 auto;
33 | padding-left: 50px;
34 | }
--------------------------------------------------------------------------------
/examples/build-examples.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | if not exist ..\bin\jwacs.exe echo Can't find jwacs.exe!
4 | if not exist ..\bin\jwacs.exe echo You can build the examples by evaluating
5 | if not exist ..\bin\jwacs.exe echo (asdf:oos 'asdf:load-op :jwacs-tests)
6 | if not exist ..\bin\jwacs.exe echo (jw-tests::compile-examples)
7 | if not exist ..\bin\jwacs.exe echo from the REPL.
8 | if not exist ..\bin\jwacs.exe goto end
9 |
10 | ..\bin\jwacs.exe --noinform -p /lib/=..\lib CalendarMark2.jw
11 | ..\bin\jwacs.exe --noinform Counter.jw
12 | ..\bin\jwacs.exe --noinform TrivialHttpRequest.jw
13 |
14 | :end
--------------------------------------------------------------------------------
/examples/TrivialHttpRequest.jw:
--------------------------------------------------------------------------------
1 | // TrivialHttpRequest.jw
2 | //
3 | // Demonstrates the motivating XMLHttpRequest usage pattern. Note that
4 | // JwascLib.fetchData appears synchronous (eg, returns a usable value), but is
5 | // actually using an asynchronous XMLHttpRequest request.
6 | //
7 | // All this example does is synchronously fetch the data stored in "datarows.txt"
8 | // and output it to the browser window.
9 |
10 | import "../lib/jwacs-lib.jw";
11 |
12 | function main()
13 | {
14 | document.getElementById('contentDiv').innerHTML = '
' + JwacsLib.fetchData('GET', 'dataRows.txt') + '
';
15 | }
16 |
17 | main();
18 |
--------------------------------------------------------------------------------
/lib/README:
--------------------------------------------------------------------------------
1 | This directory contains common library files for the examples in the examples/
2 | directory. Anything that is linked to with a URI path starting with "/lib/"
3 | lives here.
4 |
5 | jwacs-specific files:
6 |
7 | jwacs-lib.jw - This is an example of some of the library functions that can be
8 | built using jwacs.
9 | README - This file
10 |
11 | Third-party files:
12 |
13 | prototype.js - Sam Stephenson's popular Prototype library
14 | scriptaculous.js - Thomas Fuch's Script.aculo.us library
15 | builder.js - "
16 | controls.js - "
17 | dragdrop.js - "
18 | effects.js - "
19 | slider.js - "
20 |
--------------------------------------------------------------------------------
/CREDITS:
--------------------------------------------------------------------------------
1 | James Wright is the author of jwacs; he did the lexer, the Lispworks
2 | parser and most of the source transformations, as well as all of the
3 | static analysis and example code.
4 |
5 | Greg Smolyn has contributed a great deal of code. He added support
6 | for cl-yacc and did most of the other work for getting jwacs to
7 | compile under SBCL. He also made some extensive grammar changes to
8 | make the grammar unambiguous, and added support for loops (by writing
9 | the loop-transformation and adding loop methods to the
10 | cps-transformation). He also wrote the ugly-printer and
11 | uniquification transformation, and the initial error-reporting support
12 | in the lexer.
13 |
14 | Brian Patt contributed bug reports that helped track down a serious
15 | omission in the cps transformation.
16 |
17 | Pascal Bourguignon contributed a patch to get jwacs compiling under
18 | Allegro Common Lisp.
19 |
20 | Danny Stillebroer contributed several bug reports, and did the bulk of
21 | the debugging for most of them.
22 |
--------------------------------------------------------------------------------
/tests/lang-tests.template:
--------------------------------------------------------------------------------
1 |
2 |
3 | jwacs language tests
4 | <@ jwacs_imports @>
5 |
6 |
7 |
jwacs language tests
8 |
9 | This html file is a wrapper that runs the portion of the jwacs unit tests that
10 | are actually written in jwacs. The tests themselves are located in
11 | lang-tests.jw.
12 | That file needs to be compiled into lang-tests.js
13 | before changes will be reflected in the tests run by this file. You can compile
14 | by
15 |
16 |
typing (jw-tests::compile-lang-tests) from the REPL, or
17 |
typing jwacs -r ..\jw-runtime.js lang-tests.html from the command-line
18 | (this assumes that you've built the binary)
19 |
20 |
21 |
22 | Everything after the next heading is output from the automated tests.
23 |
24 |
test output
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | jwacs is distributed under the MIT License:
2 |
3 | Copyright (c) 2005-2006 James Wright and others
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/examples/WebIdeClient.template:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jwacs editor
5 |
6 |
7 |
8 |
";
21 | }
22 |
23 | function keyCount(obj)
24 | {
25 | var count = 0;
26 |
27 | var dummyObj = new Object;
28 |
29 | for(var i in obj)
30 | {
31 | if(dummyObj[i])
32 | continue;
33 | count++;
34 | }
35 | return count;
36 | }
37 |
38 | function click(delta)
39 | {
40 | var newVal = counter + delta;
41 | JwacsLib.newPage("Hash Counter " + newVal, {newVal: newVal});
42 | counter = newVal;
43 | draw();
44 | }
45 |
46 | function draw()
47 | {
48 | $('counter').innerHTML = counter;
49 | $('thunkSize').innerHTML = keyCount(JwacsLib.pageThunks);
50 | $('provenancePara').innerHTML = "From newPage";
51 | }
52 |
--------------------------------------------------------------------------------
/RELEASE-NOTES:
--------------------------------------------------------------------------------
1 | ====================================================================================================
2 | alpha2 release (Sep 19/2006):
3 | --------------------------------
4 | This is the first public release of jwacs. New in this release:
5 |
6 | * The parser now performs automatic semicolon insertion
7 | * Syntax errors now include file name and line/column position
8 | * Added compress and combine/bundle modes for more compact output Javascript
9 | * BUILD-APP now allows in-memory compilation (this is mostly to support the
10 | web-based debugger)
11 | * Miscellaneous bugfixes
12 |
13 | We still transform all code instead of just those functions that are on a
14 | potential call path to a continuation operator, so the output is quite large.
15 |
16 | ====================================================================================================
17 | alpha1 release (August 14/2006):
18 | --------------------------------
19 | This is the initial "friends and family" release. Error reporting is pretty
20 | scant, and the context-based optimizations are not yet in, so it definitely
21 | requires a bit of work to get everything working properly.
22 |
23 | ====================================================================================================
24 | CURRENT KNOWN ISSUES (as of alpha2):
25 | ------------------------------------
26 | * Objects may have an unexpected field named $init during construction.
27 | * Function.apply cannot be used to call functions that have been transformed (in
28 | other words, it should only be used on functions such as library functions that
29 | have definitely not been transformed).
30 | * The with statement is not supported at all
31 | * finally clauses are not supported
32 |
--------------------------------------------------------------------------------
/jwacs-tests.asd:
--------------------------------------------------------------------------------
1 | ;;;; jwacs-tests.asd
2 | ;;;
3 | ;;; Defines an asdf system containing unit tests for jwacs.
4 |
5 | (defpackage :jwacs-tests-system
6 | (:use :cl :asdf :uiop)
7 | (:nicknames :jw-tests-system))
8 | (in-package :jwacs-tests-system)
9 |
10 | ;;;; ======= Custom ASDF file types ================================================================
11 | (defclass jwacs-file (static-file)
12 | ((type :initform "jw")))
13 |
14 | ;;;; ======= System definition =====================================================================
15 | (defsystem "jwacs-tests"
16 | :author "James Wright , Greg Smolyn "
17 | :license "MIT License "
18 | :description "Unit tests for jwacs"
19 | :serial t
20 | :components
21 | ((:module "external"
22 | :components
23 | ((:file "rt")))
24 | (:module "tests"
25 | :serial t
26 | :components
27 | ((:file "package")
28 | (:file "test-utils")
29 | (:file "test-lexer")
30 | (:file "test-parser")
31 | (:file "test-pretty-print")
32 | (:file "test-static-analysis")
33 | (:file "test-type-analysis")
34 | (:file "test-ugly-print")
35 | (:file "test-source-transformations")
36 | (:file "test-shift-decls-transformation")
37 | (:file "test-explicitize")
38 | (:file "test-shadow-values-transformation")
39 | (:file "test-cps-transformation")
40 | (:file "test-loop-transformation")
41 | (:file "test-trampoline-transformation")
42 | (:file "test-runtime-transformation")
43 | (:jwacs-file "lang-tests"))))
44 | :depends-on ("jwacs")
45 | :perform (test-op (o c) (symbol-call :jw-tests :do-tests)))
46 |
--------------------------------------------------------------------------------
/examples/CalendarMark2.css:
--------------------------------------------------------------------------------
1 | div#StatusDisplay
2 | {
3 | background: red;
4 | color: white;
5 | position: absolute;
6 | right: 5%;
7 | top: 6pt;
8 | padding: 2px 2px 2px 2px;
9 | }
10 |
11 | h2#monthTitle
12 | {
13 | margin-top: 0pt;
14 | margin-bottom: 6pt;
15 | margin-left: 5%;
16 | text-align: left;
17 | font-family: Garamond, Times New Roman, serif;
18 | font-weight: bold;
19 | font-size: 30pt;
20 | }
21 |
22 | a.navLink
23 | {
24 | color: blue;
25 | cursor: pointer;
26 | text-decoration: none;
27 | }
28 |
29 | table#monthTable
30 | {
31 | width: 90%;
32 | align: center;
33 | border-collapse: collapse;
34 | border: 1px solid #C0C0C0;
35 | min-height: 600px;
36 | }
37 |
38 | table#monthTable td
39 | {
40 | width: 14%;
41 | padding: 2px 2px 2px 2px;
42 | border: 1px solid #C0C0C0;
43 | vertical-align: top;
44 | }
45 |
46 | table#monthTable th
47 | {
48 | padding: 2px 2px 2px 2px;
49 | border: 1px solid #C0C0C0;
50 | }
51 |
52 | tr.dataRow
53 | {
54 | height: 5em;
55 | }
56 |
57 | div.dayHeader
58 | {
59 | width: 100%;
60 | text-align: right;
61 | }
62 |
63 | td.sameMonthDay div.dayHeader
64 | {
65 | font-weight: bold;
66 | }
67 |
68 | td.otherMonthDay div.dayHeader
69 | {
70 | color: gray;
71 | }
72 |
73 | span.todayDay
74 | {
75 | background-color: #ffcccc;
76 | border: 1px solid red;
77 | padding:2px 2px 2px 2px;
78 | }
79 |
80 | div.eventBox
81 | {
82 | margin-bottom: 4px;
83 | cursor: pointer;
84 | }
85 |
86 | td.sameMonthDay div.eventBox
87 | {
88 | border: 1px solid #ACAC62;
89 | background-color: #EAEAD7;
90 | color: blue;
91 | }
92 |
93 | td.sameMonthDay textarea.inplaceEditor
94 | {
95 | width: 100%;
96 | border: 1px inset #ACAC62;
97 | background-color: #EAEAD7;
98 | color: blue;
99 | }
100 |
101 | td.otherMonthDay div.eventBox
102 | {
103 | border: 1px solid #E0E0E0;
104 | background-color: #F0F0F0;
105 | color: #888888;
106 | }
107 |
108 | td.otherMonthDay textarea.inplaceEditor
109 | {
110 | width: 100%;
111 | border: 1px inset #E0E0E0;
112 | background-color: #F0F0F0;
113 | color: #888888;
114 | }
--------------------------------------------------------------------------------
/lib/scriptaculous.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining
4 | // a copy of this software and associated documentation files (the
5 | // "Software"), to deal in the Software without restriction, including
6 | // without limitation the rights to use, copy, modify, merge, publish,
7 | // distribute, sublicense, and/or sell copies of the Software, and to
8 | // permit persons to whom the Software is furnished to do so, subject to
9 | // the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be
12 | // included in all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 | var Scriptaculous = {
23 | Version: '1.6.1',
24 | require: function(libraryName) {
25 | // inserting via DOM fails in Safari 2.0, so brute force approach
26 | document.write('');
27 | },
28 | load: function() {
29 | if((typeof Prototype=='undefined') ||
30 | (typeof Element == 'undefined') ||
31 | (typeof Element.Methods=='undefined') ||
32 | parseFloat(Prototype.Version.split(".")[0] + "." +
33 | Prototype.Version.split(".")[1]) < 1.5)
34 | throw("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0");
35 |
36 | $A(document.getElementsByTagName("script")).findAll( function(s) {
37 | return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
38 | }).each( function(s) {
39 | var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
40 | var includes = s.src.match(/\?.*load=([a-z,]*)/);
41 | (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each(
42 | function(include) { Scriptaculous.require(path+include+'.js') });
43 | });
44 | }
45 | }
46 |
47 | Scriptaculous.load();
--------------------------------------------------------------------------------
/conditions.lisp:
--------------------------------------------------------------------------------
1 | ;;;; conditions.lisp
2 | ;;;
3 | ;;; Defines the hierarchy of custom conditions that are used by jwacs
4 | ;;;
5 | ;;; Copyright (c) 2006 by James Wright
6 | ;;;
7 | (in-package :jwacs)
8 |
9 | (define-condition positioned-condition (condition)
10 | ((filename :initarg :filename :initform nil :reader filename)
11 | (pos :initarg :pos :reader pos)
12 | (row :initarg :row :reader row)
13 | (column :initarg :column :reader column))
14 | (:documentation "Represents a condition that has a source position associated with it"))
15 |
16 | (define-condition syntax-error (error positioned-condition)
17 | ((token :initarg :token :reader token)
18 | (expected-terminals :initarg :expected-terminals :reader expected-terminals))
19 | (:documentation "Indicates that an error occured during parsing"))
20 |
21 | (defmethod print-object ((e syntax-error) s)
22 | (unless (and (slot-boundp e 'row)
23 | (slot-boundp e 'column)
24 | (slot-boundp e 'token))
25 | (return-from print-object (call-next-method)))
26 |
27 | (cond
28 | (*print-escape*
29 | (print-unreadable-object (e s :type t :identity nil)
30 | (format s "~A (~D,~D): Unexpected terminal ~S"
31 | (or (filename e) "")
32 | (row e) (column e)
33 | (or (token-terminal (token e)) 'eof))))
34 | ((slot-boundp e 'expected-terminals)
35 | (format s "~A (~D,~D): Unexpected terminal ~S (value: ~S)~%~
36 | Expected one of ~S"
37 | (or (filename e) "")
38 | (row e) (column e)
39 | (or (token-terminal (token e)) 'eof) (token-value (token e))
40 | (expected-terminals e)))
41 | (t
42 | (format s "~A (~D,~D): Unexpected terminal ~S (value: ~S)"
43 | (or (filename e) "")
44 | (row e) (column e)
45 | (or (token-terminal (token e)) 'eof) (token-value (token e))))))
46 |
47 | (define-condition missing-import (error positioned-condition)
48 | ((parent-uripath :initarg :parent-uripath :reader parent-uripath) ; Name of the module where the bad import occurs
49 | (import-uripath :initarg :import-uripath :reader import-uripath)) ; URI-path of the missing import
50 | (:documentation "Indicates that an import could not be located"))
51 |
52 | (defmethod print-object ((e missing-import) s)
53 | (unless (and (slot-boundp e 'row)
54 | (slot-boundp e 'column)
55 | (slot-boundp e 'parent-uripath)
56 | (slot-boundp e 'import-uripath))
57 | (return-from print-object (call-next-method)))
58 |
59 | (if *print-escape*
60 | (print-unreadable-object (e s :type t :identity nil)
61 | (format s "~A:~D,~D: Missing import ~S" (parent-uripath e) (row e) (column e) (import-uripath e)))
62 | (format s "~A:~D,~D: Missing import ~S" (parent-uripath e) (row e) (column e) (import-uripath e))))
63 |
--------------------------------------------------------------------------------
/jwacs.asd:
--------------------------------------------------------------------------------
1 | ;;;; jwacs.asd
2 | ;;;
3 | ;;; This is the system definition file for the jwacs project.
4 | ;;; It defines the asdf system plus any extra asdf operations
5 | ;;; (eg test-op).
6 |
7 | (defpackage :jwacs-system
8 | (:use :cl :asdf)
9 | (:nicknames :jw-system))
10 | (in-package :jwacs-system)
11 |
12 | ;;;; ======= Compilation configuration =============================================================
13 | (defparameter *muffle-conflicts* t
14 | "When T, yacc warnings about Shift/Reduce and Reduce/Reduce conflicts will be muffled.
15 | When NIL, all such conflicts will be reported.
16 | When non-NIL, non-T, a single summary warning will be reported when conflicts exist.
17 |
18 | This value should be set to NIL or non-T during grammar
19 | development/debugging (so that we find out about the conflicts), but T
20 | at all other times (so that SBCL won't drop into the debugger when
21 | we're trying to load parse-javascript.lisp).")
22 |
23 | ;;;; ======= Custom ASDF file types ================================================================
24 | (defclass js-file (static-file)
25 | ((type :initform "js")))
26 |
27 | ;;;; ======= System definition =====================================================================
28 | (defsystem "jwacs"
29 | :version "0.3"
30 | :author "James Wright et al"
31 | :license "MIT License "
32 | :description "Javascript With Advanced Continuation Support"
33 | :serial t
34 | :class program-system
35 | :build-operation program-op
36 | :build-pathname "jwacs"
37 | :entry-point "jwacs:main"
38 | :components ((:module "external"
39 | :components
40 | ((:file "yacc")))
41 | ;;TODO Should these three non-Lisp files go into a separate module?
42 | (:js-file "jw-runtime")
43 | (:js-file "jw-debug-runtime")
44 | (:html-file "default-template")
45 | (:html-file "default-iframe")
46 | (:file "package")
47 | (:file "general-utilities")
48 | (:file "conditions")
49 | (:file "lexer-macros")
50 | (:file "lex-javascript")
51 | (:file "js-source-model")
52 | (:file "parse-javascript-yacc")
53 | (:file "parse-javascript")
54 | (:file "pretty-print")
55 | (:file "source-transformations")
56 | (:file "shift-decls-transformation")
57 | (:file "ugly-print")
58 | (:file "static-analysis")
59 | (:file "type-analysis")
60 | (:file "explicitize-transformation")
61 | (:file "shadow-values-transformation")
62 | (:file "cps-transformation")
63 | (:file "loop-transformation")
64 | (:file "trampoline-transformation")
65 | (:file "runtime-transformation")
66 | (:file "compiler")
67 | (:file "main"))
68 | :depends-on ("cl-ppcre")
69 | :in-order-to ((test-op (test-op "jwacs-tests"))))
70 |
--------------------------------------------------------------------------------
/examples/textarea-highlights.js:
--------------------------------------------------------------------------------
1 | var activeBoxes = [];
2 |
3 | function getHeight(dummyDiv, text)
4 | {
5 | while(dummyDiv.lastChild)
6 | dummyDiv.removeChild(dummyDiv.lastChild);
7 |
8 | var paras = text.split(/\r?\n/);
9 | for(var i = 0; i < paras.length; i++)
10 | {
11 | if(i > 0)
12 | dummyDiv.appendChild(document.createElement("BR"));
13 | dummyDiv.appendChild(document.createTextNode(paras[i]));
14 | }
15 |
16 | return dummyDiv.offsetHeight;
17 | }
18 |
19 | function findBoundingYs(dummyDiv, text, s, e)
20 | {
21 | var lineHeight = getHeight(dummyDiv, 'a');
22 | var precedingHeight = s == 0 ? lineHeight : getHeight(dummyDiv, text.substr(0, s));
23 | var includingHeight = getHeight(dummyDiv, text.substr(0, e));
24 |
25 | return [lineHeight + includingHeight - precedingHeight, precedingHeight - lineHeight];
26 | }
27 |
28 | function positionBoxes()
29 | {
30 | for(var i = 0; i < activeBoxes.length; i++)
31 | {
32 | var box = activeBoxes[i];
33 | var elm = box._targetElm;
34 |
35 | var top = box._heightAndTop[1];
36 | var bot = top + box._heightAndTop[0];
37 |
38 | top = Math.max(top, elm.scrollTop);
39 | bot = Math.min(bot, elm.scrollTop + elm.clientHeight);
40 |
41 | if(top < bot)
42 | {
43 | box.style.top = (top + elm.offsetTop - elm.scrollTop) + 'px';
44 | box.style.height = (bot - top) + 'px';
45 | box.style.width = (elm.clientWidth + tabWidth + 3) + 'px';
46 | box.style.left = (Position.positionedOffset(elm)[0] - tabWidth) + 'px';
47 | Element.show(box);
48 | }
49 | else
50 | Element.hide(box);
51 | }
52 | }
53 |
54 | //======= Public API ===============================================================================
55 |
56 | var tabWidth = 0;
57 | function addHighlight(elm, dummyDiv, s, e, background)
58 | {
59 | var box = document.createElement("DIV");
60 | var origScroll = elm.scrollTop;
61 | var heightAndTop = findBoundingYs(dummyDiv, elm.value, s, e);
62 |
63 | Element.hide(box);
64 | Element.setOpacity(box, 0.5);
65 | box.style.position = 'absolute';
66 | box.style.background = background || 'green';
67 |
68 | box._heightAndTop = heightAndTop;
69 | box._targetElm = elm;
70 |
71 | document.body.appendChild(box);
72 | activeBoxes.push(box);
73 | elm.scrollTop = origScroll;
74 |
75 | return box;
76 | }
77 |
78 | function removeHighlight(targetBox)
79 | {
80 | for(var i = 0; i < activeBoxes.length; i++)
81 | {
82 | var box = activeBoxes[i];
83 | if(box == targetBox)
84 | {
85 | activeBoxes[i] = null;
86 | activeBoxes.splice(i, 1);
87 | box.parentNode.removeChild(box);
88 | return box;
89 | }
90 | }
91 | }
92 |
93 | function clearHighlights()
94 | {
95 | for(var i = 0; i < activeBoxes.length; i++)
96 | {
97 | var box = activeBoxes[i];
98 | box.parentNode.removeChild(box);
99 | activeBoxes[i] = null;
100 | }
101 | activeBoxes = [];
102 | }
103 |
104 | function initHighlights(period)
105 | {
106 | setInterval(positionBoxes, period || 150);
107 | }
108 |
--------------------------------------------------------------------------------
/parse-javascript-yacc.lisp:
--------------------------------------------------------------------------------
1 | ;;;; parse-javascript-yacc.lisp
2 | ;;;
3 | ;;; Use the cl-yacc package to parse javascript source text.
4 | ;;;
5 | ;;; Copyright (c) 2005 Greg Smolyn
6 | ;;; See LICENSE for full licensing details.
7 | ;;;
8 | (in-package :jwacs)
9 |
10 | (defun expand-hashtable-to-values (hashtable)
11 | "Returns a list of all the values stored in a hashtable."
12 | (let ((valuelist '()))
13 | (maphash #'(lambda (k v)
14 | (declare (ignore k))
15 | (setf valuelist (cons v valuelist)))
16 | hashtable)
17 | valuelist))
18 |
19 | ; need to collect productions
20 |
21 | (defmacro defparser (parser-name starting-production &body productions)
22 | "This macro emulates the Lispworks parsergenerator's defparser macro, but instead creates output
23 | for CL-YACC"
24 | (let* ((starting-point (first starting-production))
25 | (starting-symbol (first starting-point))
26 | (header `(yacc:define-parser ,parser-name
27 | (:muffle-conflicts ,jwacs-system::*muffle-conflicts*)
28 | ; (:print-derives-epsilon t)
29 | ; (:print-first-terminals t)
30 | ; (:print-states t)
31 | ; (:print-goto-graph t)
32 | ; (:print-lookaheads )
33 | (:start-symbol ,starting-symbol)
34 | (:terminals ,(expand-hashtable-to-values *tokens-to-symbols* ))
35 | (:precedence nil)
36 | ,starting-point)))
37 | (append header (generate-productions productions))))
38 |
39 | ; here we turn
40 | ; ((primary-expression object-literal) $1)
41 | ; into
42 | ; (primary-expression
43 | ; (object-literal #'(lambda (&rest expr) (nth 0 expr))))
44 | ;
45 | ; and
46 | ;
47 | ; ((literal :number) (make-numeric-literal :value $1))
48 | ; into
49 | ; (literal
50 | ; (:number #'(lambda (&rest expr) (make-numeric-literal :value (nth 0 expr)))))
51 |
52 |
53 |
54 | (defun generate-productions (productions)
55 | "Used by defparser macro. Take the lispworks list of productions and convert them into
56 | CL-YACC versions"
57 | (let* ((production-map (make-hash-table)))
58 | (dolist (production productions)
59 | (let* ((rule (nth 0 production))
60 | (action (maptree 'replace-special-variables (nth 1 production)))
61 | (rule-name (first rule))
62 | (rule-terminals (rest rule)))
63 | (setf (gethash rule-name production-map)
64 | (cons (append rule-terminals `(#'(lambda (&rest expr) ,action)))
65 | (gethash rule-name production-map)))))
66 | (let* ((output '()))
67 | (maphash #'(lambda (k v)
68 | (setf output (cons (append (list k) (reverse v)) output)))
69 | production-map)
70 | (reverse output))))
71 |
72 | (defun replace-special-variables (leaf)
73 | "Replace $$n with (token-value (nth n-1 expr)) and $n with (nth n-1 expr)"
74 | (if (symbolp leaf)
75 | (let ((symname (symbol-name leaf)))
76 | (cond
77 | ((string= symname "$S")
78 | `(element-start expr))
79 | ((string= symname "$E")
80 | `(element-end expr))
81 | ((prefix-p symname "$$")
82 | `(token-value (nth ,(1- (parse-integer (subseq symname 2))) expr)))
83 | ((prefix-p symname "$")
84 | `(nth ,(1- (parse-integer (subseq symname 1))) expr))
85 | (t
86 | leaf)))
87 | leaf))
88 |
--------------------------------------------------------------------------------
/lib/builder.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 | //
3 | // See scriptaculous.js for full license.
4 |
5 | var Builder = {
6 | NODEMAP: {
7 | AREA: 'map',
8 | CAPTION: 'table',
9 | COL: 'table',
10 | COLGROUP: 'table',
11 | LEGEND: 'fieldset',
12 | OPTGROUP: 'select',
13 | OPTION: 'select',
14 | PARAM: 'object',
15 | TBODY: 'table',
16 | TD: 'table',
17 | TFOOT: 'table',
18 | TH: 'table',
19 | THEAD: 'table',
20 | TR: 'table'
21 | },
22 | // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
23 | // due to a Firefox bug
24 | node: function(elementName) {
25 | elementName = elementName.toUpperCase();
26 |
27 | // try innerHTML approach
28 | var parentTag = this.NODEMAP[elementName] || 'div';
29 | var parentElement = document.createElement(parentTag);
30 | try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
31 | parentElement.innerHTML = "<" + elementName + ">" + elementName + ">";
32 | } catch(e) {}
33 | var element = parentElement.firstChild || null;
34 |
35 | // see if browser added wrapping tags
36 | if(element && (element.tagName != elementName))
37 | element = element.getElementsByTagName(elementName)[0];
38 |
39 | // fallback to createElement approach
40 | if(!element) element = document.createElement(elementName);
41 |
42 | // abort if nothing could be created
43 | if(!element) return;
44 |
45 | // attributes (or text)
46 | if(arguments[1])
47 | if(this._isStringOrNumber(arguments[1]) ||
48 | (arguments[1] instanceof Array)) {
49 | this._children(element, arguments[1]);
50 | } else {
51 | var attrs = this._attributes(arguments[1]);
52 | if(attrs.length) {
53 | try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
54 | parentElement.innerHTML = "<" +elementName + " " +
55 | attrs + ">" + elementName + ">";
56 | } catch(e) {}
57 | element = parentElement.firstChild || null;
58 | // workaround firefox 1.0.X bug
59 | if(!element) {
60 | element = document.createElement(elementName);
61 | for(attr in arguments[1])
62 | element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
63 | }
64 | if(element.tagName != elementName)
65 | element = parentElement.getElementsByTagName(elementName)[0];
66 | }
67 | }
68 |
69 | // text, or array of children
70 | if(arguments[2])
71 | this._children(element, arguments[2]);
72 |
73 | return element;
74 | },
75 | _text: function(text) {
76 | return document.createTextNode(text);
77 | },
78 | _attributes: function(attributes) {
79 | var attrs = [];
80 | for(attribute in attributes)
81 | attrs.push((attribute=='className' ? 'class' : attribute) +
82 | '="' + attributes[attribute].toString().escapeHTML() + '"');
83 | return attrs.join(" ");
84 | },
85 | _children: function(element, children) {
86 | if(typeof children=='object') { // array can hold nodes and text
87 | children.flatten().each( function(e) {
88 | if(typeof e=='object')
89 | element.appendChild(e)
90 | else
91 | if(Builder._isStringOrNumber(e))
92 | element.appendChild(Builder._text(e));
93 | });
94 | } else
95 | if(Builder._isStringOrNumber(children))
96 | element.appendChild(Builder._text(children));
97 | },
98 | _isStringOrNumber: function(param) {
99 | return(typeof param=='string' || typeof param=='number');
100 | }
101 | }
--------------------------------------------------------------------------------
/tests/test-shift-decls-transformation.lisp:
--------------------------------------------------------------------------------
1 | ;;;; test-shift-function-decls.lisp
2 | ;;;
3 | ;;; Tests for the shift-decls transformation
4 | ;;;
5 | ;;; Copyright (c) 2005 James Wright
6 | ;;; See LICENSE for full licensing details.
7 | ;;;
8 | (in-package :jwacs-tests)
9 |
10 | (defnote shift-decls "Tests for the shift-decls transformation")
11 |
12 | (deftest shift-decls/1 :notes shift-decls
13 | (transform 'shift-decls (test-parse "
14 | var global1, global2 = 20;
15 | WScript.echo(global2);
16 | function foo()
17 | {
18 | bar();
19 | var a = 10;
20 | function inner(h)
21 | {
22 | return h * 10;
23 | }
24 | var b = 20;
25 | }
26 | var global3 = /h/g;
27 | function bar() { return -88; }"))
28 | #.(test-parse "
29 | var global1;
30 | var global2;
31 | var global3;
32 | function foo()
33 | {
34 | function inner(h)
35 | {
36 | return h * 10;
37 | }
38 | bar();
39 | var a = 10;
40 | var b = 20;
41 | }
42 | function bar() { return -88; }
43 | global2 = 20;
44 | WScript.echo(global2);
45 | global3 = /h/g;"))
46 |
47 |
48 | (deftest shift-decls/2 :notes shift-decls
49 | (transform 'shift-decls (test-parse "
50 | function foo()
51 | {
52 | var a = 1;
53 | if(x)
54 | {
55 | var b;
56 | var fex = function functionExpression() // Doesn't move; only function decls move
57 | {
58 | return inner(2);
59 | function inner(arg) { return arg; } // Moves up within functionExpression's body only
60 | };
61 | var c = 100;
62 | }
63 | }"))
64 | #.(test-parse "
65 | function foo()
66 | {
67 | var a = 1;
68 | if(x)
69 | {
70 | var b;
71 | var fex = function functionExpression()
72 | {
73 | function inner(arg) { return arg; }
74 | return inner(2);
75 | };
76 | var c = 100;
77 | }
78 | }"))
79 |
80 | (deftest shift-decls/3 :notes shift-decls
81 | (transform 'shift-decls (test-parse "
82 | var obj = { field: 44, method: function() { return this.field * 2; }};
83 | function fn()
84 | {
85 | obj.method(obj.field);
86 | }"))
87 | #.(test-parse "
88 | var obj;
89 | function fn()
90 | {
91 | obj.method(obj.field);
92 | }
93 | obj = { field: 44, method: function() { return this.field * 2; }};"))
94 |
95 | (deftest shift-decls/nested-var-decls/1 :notes shift-decls
96 | (transform 'shift-decls (test-parse "
97 | foo();
98 | var x = 10;
99 | try
100 | {
101 | var y = 20;
102 | }
103 | catch(e)
104 | {
105 | bar(e);
106 | }"))
107 | #.(test-parse "
108 | var x;
109 | var y;
110 | foo();
111 | x = 10;
112 | try
113 | {
114 | y = 20;
115 | }
116 | catch(e)
117 | {
118 | bar(e);
119 | }"))
120 |
121 | (deftest shift-decls/nested-var-decls/2 :notes shift-decls
122 | (transform 'shift-decls (test-parse "
123 | foo();
124 | var x = 10;
125 | try
126 | {
127 | var y = 20;
128 | }
129 | catch(e)
130 | {
131 | var z;
132 | bar(e);
133 | }"))
134 | #.(test-parse "
135 | var x;
136 | var y;
137 | var z;
138 | foo();
139 | x = 10;
140 | try
141 | {
142 | y = 20;
143 | }
144 | catch(e)
145 | {
146 | bar(e);
147 | }"))
148 |
149 | (deftest shift-decls/position-preservation/1 :notes shift-decls
150 | (transform 'shift-decls (parse "foo(); var x = bar();"))
151 | (#s(var-decl-statement :var-decls (#s(var-decl :name "x")))
152 | #s(fn-call :fn #s(identifier :name "foo" :start 0 :end 3)
153 | :args nil
154 | :start 0 :end 3)
155 | #s(binary-operator :left-arg #s(identifier :name "x")
156 | :op-symbol :assign
157 | :right-arg #s(fn-call :fn #s(identifier :name "bar" :start 15 :end 18)
158 | :args nil
159 | :start 15 :end 18)
160 | :start 11 :end 18)))
--------------------------------------------------------------------------------
/shadow-values-transformation.lisp:
--------------------------------------------------------------------------------
1 | ;;;; shadow-values-transformation.lisp
2 | ;;;
3 | ;;; Defines the shadow-values transformation, which replaces references to
4 | ;;; `this` and `arguments` (which don't behave as expected when you're at
5 | ;;; the bottom of three levels of continuation) with references to "shadow
6 | ;;; values", which are variable that have been set to point to the /correct/
7 | ;;; versions of `this` and arguments at the beginning of a function.
8 | ;;;
9 | ;;; Copyright (c) 2006 James Wright
10 | ;;; See LICENSE for full licensing details.
11 | ;;;
12 | (in-package :jw)
13 |
14 | (defparameter *shadowed-this-name* nil
15 | "Name of the variable that currently shadows `this`")
16 |
17 | (defparameter *shadowed-arguments-name* nil
18 | "Name of the variable that currently shadows `arguments`")
19 |
20 | (defparameter *arguments-name* "arguments"
21 | "Name of the `arguments` identifier")
22 |
23 | (defmethod transform ((xform (eql 'shadow-values)) (elm identifier))
24 | (if (and *shadowed-arguments-name*
25 | (equal (identifier-name elm) *arguments-name*))
26 | (make-identifier :name *shadowed-arguments-name*
27 | :start (source-element-start elm)
28 | :end (source-element-end elm))
29 | (call-next-method)))
30 |
31 | (defmethod transform ((xform (eql 'shadow-values)) (elm special-value))
32 | (if (and *shadowed-this-name*
33 | (eq :this (special-value-symbol elm)))
34 | (make-identifier :name *shadowed-this-name*
35 | :start (source-element-start elm)
36 | :end (source-element-end elm))
37 | (call-next-method)))
38 |
39 | (defun tx-shadow-values-body (body)
40 | "Transforms the body of a function expression or declaration and returns
41 | the new body"
42 | (let* ((declares-arguments-p (find *arguments-name*
43 | (collect-in-scope body 'var-decl)
44 | :key 'var-decl-name :test 'equal))
45 | (references-arguments-p (find *arguments-name*
46 | (collect-in-scope body 'identifier)
47 | :key 'identifier-name :test 'equal))
48 | (references-this-p (find :this
49 | (collect-in-scope body 'special-value)
50 | :key 'special-value-symbol :test 'eq))
51 | (*shadowed-arguments-name* (if (and references-arguments-p (not declares-arguments-p))
52 | (genvar "arguments")
53 | nil))
54 | (*shadowed-this-name* (if references-this-p
55 | (genvar "this")
56 | nil)))
57 | (cond
58 |
59 | ((and references-arguments-p (not declares-arguments-p)
60 | references-this-p)
61 | (append
62 | (list (make-var-init *shadowed-arguments-name* (make-special-value :symbol :arguments))
63 | (make-var-init *shadowed-this-name* (make-special-value :symbol :this)))
64 | (transform 'shadow-values body)))
65 |
66 | ((and references-arguments-p (not declares-arguments-p))
67 | (cons (make-var-init *shadowed-arguments-name* (make-special-value :symbol :arguments))
68 | (transform 'shadow-values body)))
69 |
70 | (references-this-p
71 | (cons (make-var-init *shadowed-this-name* (make-special-value :symbol :this))
72 | (transform 'shadow-values body)))
73 |
74 | (t
75 | (transform 'shadow-values body)))))
76 |
77 |
78 | (defmethod transform ((xform (eql 'shadow-values)) (elm function-decl))
79 | (make-function-decl :name (function-decl-name elm)
80 | :parameters (function-decl-parameters elm)
81 | :body (tx-shadow-values-body (function-decl-body elm))
82 | :start (source-element-start elm)
83 | :end (source-element-end elm)))
84 |
85 | (defmethod transform ((xform (eql 'shadow-values)) (elm function-expression))
86 | (make-function-expression :name (function-expression-name elm)
87 | :parameters (function-expression-parameters elm)
88 | :body (tx-shadow-values-body (function-expression-body elm))
89 | :start (source-element-start elm)
90 | :end (source-element-end elm)))
--------------------------------------------------------------------------------
/doc/examples.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jwacs examples
5 |
6 |
50 |
51 |
52 |
53 |
jwacs examples
54 | The examples/ directory contains some small (tiny) example
55 | applications written in jwacs. This file provides descriptions of
56 | them.
57 |
58 |
You can build all of the example programs by running the
59 | build-examples script (under Linux) or the
60 | build-examples.cmd batch file (under Windows). You can also execute
61 | the following from the REPL:
62 |
63 |
Some of the example programs (okay, one) require the server to provide
68 | certain services for Ajax requests, so they (okay, it) won't run very well on
69 | a local file system. So that you can still see these (this) application in
70 | action, we provide running versions of all the example apps on the
71 | jwacs site.
72 |
73 |
74 |
TrivialHttpRequest
75 |
This trivial little app demonstrates the use of
76 | JwacsLib.fetchData; it fetches a text file from the server and
77 | displays it on the page. Note that it is making an asynchronous
78 | XMLHttpRequest request, but to the programmer it appears that
79 | fetchData blocks until complete and then returns the result.
80 |
81 |
Counter
82 |
This application shows a simple counter, and links to make it go up and
83 | down. It demonstrates the use of the history (ie, back-button) management
84 | capabilities that the jwacs library provides.
85 |
86 |
Calendar Mark 2
87 |
This slightly more substantial example of a jwacs application implements
88 | a simple web-calendar as a client-side application. Login using username
89 | guest and password guest.
90 |
91 |
The client expects the server to provide a basic REST-style service that
92 | exposes the following endpoints:
93 |
94 |
GET /event-query with parameter id: Returns a single event
95 |
GET /event-query with parameters s and e:
96 | Returns all events that occur between the start date s
97 | and the end date e inclusive.
98 |
POST /event-add with parameters date, desc,
99 | and notes: Creates a new event on the specified date with the
100 | specified description and notes. Returns the created event if successful.
101 |
POST /event-del with parameter id: Deletes the
102 | specified event.
103 |
POST /event-update with required parameter id and
104 | optional parameters date, desc, and notes:
105 | Updates the specified fields of the specified event.
106 |
107 |
108 |
109 |
Unit tests
110 |
111 | The jwacs-tests system contains a bunch of unit tests that verify
112 | that the transformations produce the code that we expect them to. To run
113 | these unit tests, execute the following from the REPL:
114 |
115 | (asdf:oos 'asdf:test-op :jwacs)
116 |
117 |
Language tests
118 | The tests/ directory also contains "language tests" to verify that
119 | transformed code behaves as expected. To run these tests, execute
120 |
121 |