├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── doc └── intro.md ├── project.clj ├── resources └── wisp │ ├── .DS_Store │ ├── .documentup.json │ ├── .gitignore │ ├── .npmignore │ ├── .travis.yml │ ├── History.md │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── doc │ ├── language-essentials.md │ ├── more-info.md │ └── readme-original.md │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── .DS_Store │ ├── analyzer.wisp │ ├── ast.wisp │ ├── backend │ │ ├── escodegen │ │ │ ├── generator.wisp │ │ │ └── writer.wisp │ │ └── javascript │ │ │ └── writer.wisp │ ├── browser-test-run.wisp │ ├── compiler.wisp │ ├── engine │ │ ├── browser.wisp │ │ ├── browserCompiler.wisp │ │ ├── browserExport.wisp │ │ ├── browserExportCompiler.wisp │ │ └── node.wisp │ ├── expander.wisp │ ├── reader.wisp │ ├── repl.wisp │ ├── runtime.wisp │ ├── sequence.wisp │ ├── string.wisp │ └── wisp.wisp │ └── test │ ├── analyzer.wisp │ ├── ast.wisp │ ├── compiler.wisp │ ├── escodegen.wisp │ ├── protocols.wisp │ ├── reader.wisp │ ├── runtime.wisp │ ├── sequence.wisp │ ├── string.wisp │ ├── test.wisp │ └── util.wisp ├── src └── wisp_compiler │ └── core.clj └── test └── wisp_compiler └── core_test.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## [Unreleased] 5 | ### Changed 6 | - Add a new arity to `make-widget-async` to provide a different widget shape. 7 | 8 | ## [0.1.1] - 2018-09-15 9 | ### Changed 10 | - Documentation on how to make the widgets. 11 | 12 | ### Removed 13 | - `make-widget-sync` - we're all async, all the time. 14 | 15 | ### Fixed 16 | - Fixed widget maker to keep working when daylight savings switches over. 17 | 18 | ## 0.1.0 - 2018-09-15 19 | ### Added 20 | - Files from the new template. 21 | - Widget maker public API - `make-widget-sync`. 22 | 23 | [Unreleased]: https://github.com/your-name/wispc/compare/0.1.1...HEAD 24 | [0.1.1]: https://github.com/your-name/wispc/compare/0.1.0...0.1.1 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor to control, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wisp Compiler 2 | 3 | This lets you compile [wisp](https://gozala.github.io/wisp/) forms (or strings) into Javascript 4 | 5 | [![Clojars Project](https://img.shields.io/clojars/v/px0/wisp-compiler.svg)](https://clojars.org/px0/wisp-compiler) 6 | 7 | ## Why? 8 | This allows you to embed Clojure-flavoured JavaScript into your [hiccup](http://weavejester.github.io/hiccup/), pages, e.g.: 9 | 10 | ```clojure 11 | (require '[wisp-compiler.core :as wisp]) 12 | 13 | (hiccup/html 14 | [:div 15 | [:button {:onclick (wisp/compile [] (hello-world))} "Hello!"] 16 | [:script (wisp-compile 17 | (defn hello-world [] 18 | (alert (str :Hello " World!"))))]]) 19 | ``` 20 | 21 | which will compile into 22 | ```html 23 |
24 | 25 | 30 |
31 | ``` 32 | 33 | ## Okay, but show me something useful 34 | Compiling sexps into JavaScript is neat by itself, but sometimes you want to generate JavaScript dynamically on the server (e.g. for [Server-generated JavaScript Responses](https://signalvnoise.com/posts/3697-server-generated-javascript-responses)). In this case you may have held your nose and just concatenated a bunch of strings. Here is a snippet from one of my projects (don't judge): 35 | 36 | ```clj 37 | (defn upvote-comment [commentid] 38 | (javascript-response (str "var newEl = document.createElement('span');" 39 | "newEl.innerText = 'Upvoted!';" 40 | "var el = document.getElementById(\"" commentid "\").querySelector(\"a.upvote\");" 41 | "if(el) el.replaceWith(newEl);")) 42 | ``` 43 | 44 | With wisp, this can (and should!) be rewritten like this: 45 | ```clj 46 | (defn upvote-comment [cid] 47 | (javascript-reponse 48 | (wisp/compile [commentid cid] 49 | (let [new-el (document.createElement "span") 50 | el (document.getElementById commentid) 51 | upvote (.querySelector el "a.upvote")] 52 | (if el 53 | (el.replaceWith new-el)))))) 54 | ``` 55 | 56 | Which will result in JavaScript like this: 57 | 58 | ```js 59 | // (upvote-comment "my-comment-id") 60 | 61 | (function () { 62 | var newElø1 = document.createElement('span'); 63 | var elø1 = document.getElementById('my-comment-id'); 64 | var upvoteø1 = elø1.querySelector('a.upvote'); 65 | return elø1 ? elø1.replaceWith(newElø1) : void 0; 66 | }.call(this)); 67 | ``` 68 | 69 | As you can see, the symbols referenced in the initial binding vector get automatically evaluated and inserted into the expression. This way you can not only write your JavaScript with sweet, sweet parentheses, you will also get the sexps syntax-highlighted, and you don't have to mess around with string manipulation! 70 | 71 | 72 | # Advanced usage 73 | To use the more advanced Wisp features, you'll need to include the runtime, the sequence and string libraries into the page. This should be possible by including the `resources/wisp/{runtime,sequence,string}.js` files into the page (in this order). 74 | 75 | For caching reasons, you should probably just copy them into your `public` folder, but for convenience I am also exposing them as `wisp-runtime`, `wisp-sequence`, `wisp-string`, and altogether as `wisp-includes` functions that return these files as strings 76 | 77 | # Gotchas 78 | The symbol of the resolution of the `compile` macro is dumb and will replace the given symbol with its value no matter where in the source code it is. So if you expect to be able to shadow bindings in a nested scope somewhere, it will most likely break. This is for short snippets, and you are very much responsible for reading them after compilation and making sure they work. Don't blame me if your code reaks! 79 | 80 | # Compiling wisp 81 | In the `resources/wisp` directory, run `make compiler` to re-compile the wisp compiler 82 | 83 | 84 | Copyright © 2018 Maximilian Gerlach 85 | 86 | Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version. 87 | -------------------------------------------------------------------------------- /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to wispc 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject px0/wisp-compiler "0.3.3" 2 | :description "Compile wisp expressions to JavaScript in your Clojure project!" 3 | :url "https://github.com/px0/wisp-compiler" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | ;; :deploy-repositories [["clojars" {:sign-releases false 7 | ;; :url "https://clojars.org/repo"}]] 8 | :deploy-repositories {"releases" {:url "https://repo.clojars.org" :sign-releases false}} 9 | :release-tasks [["deploy"]] 10 | :dependencies [[org.clojure/clojure "1.8.0"]]) 11 | -------------------------------------------------------------------------------- /resources/wisp/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/px0/wisp-compiler/355de33a6c64de3fdb7c73f3bc13741fa15d62c2/resources/wisp/.DS_Store -------------------------------------------------------------------------------- /resources/wisp/.documentup.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "v1", 3 | "travis": true 4 | } 5 | -------------------------------------------------------------------------------- /resources/wisp/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | src/drafts/* 3 | node_modules 4 | .*.swp 5 | workspace 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /resources/wisp/.npmignore: -------------------------------------------------------------------------------- 1 | src/drafts/* 2 | -------------------------------------------------------------------------------- /resources/wisp/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8.11.4" 4 | -------------------------------------------------------------------------------- /resources/wisp/History.md: -------------------------------------------------------------------------------- 1 | # History 2 | 3 | ## 0.10.0 4 | 5 | - Implement support for `defprotocol`, `deftype`, `defrecord`, 6 | `extend-type` and `extend-protocol` forms. 7 | 8 | ## 0.9.0 9 | 10 | - Compiler no longer does dummy string concatinations instead 11 | JS AST is emited from which `esprima` generates JS. 12 | - Implement analyzer that does analyzes read forms to add 13 | variable shadowing info, do macroexpansion etc.. 14 | - Reader now includes source location into all read forms 15 | except primitives. 16 | - Compiler generates source maps unless disabled manually. 17 | - `fn` form no longer supports clojure(script) incompatible 18 | API. 19 | - Improvements in conventional name translations. 20 | - Compiler now throws errors on invalid forms, instead of 21 | generating invalid JS. 22 | - Add support for binding shadowing in let and loop forms, 23 | now bindings defined in those forms get unique names with 24 | suffix of the shadow depth. 25 | - Bunch of reader improvements. 26 | - Macros now support special `&env` and `&form` arguments. 27 | - Enhanced CLI tool. 28 | 29 | ## 0.8.1 30 | 31 | - Remove support for third non-standard argument for `aget`. 32 | - Implement `interleave` high order function. 33 | - Implement `some` high order function. 34 | - Implement `partition` high order function. 35 | - Implement `every?` function. 36 | - Rewrite `get` as macro compiling to `aget` forms. 37 | - Make re-pattern writer. 38 | - Alias `compile*` as `compile-program`. 39 | - Implement `.` operator as a macro. 40 | - Fix `aget` with for quoted attributes `(aget foo 'bar). 41 | - Move `instance?` form expander to a writer. 42 | - Add `(debugger!)` form to generate `debugger;` statements. 43 | 44 | ## 0.8.0 45 | 46 | - Remove `:use` forms in favor of `:require`. 47 | - Remove `import` macro in favor of `:require`. 48 | 49 | ## 0.7.1 50 | 51 | - Implement `assoc` function. 52 | - Make `:use` form for imports obsolete by extending `:require`. 53 | 54 | ## 0.7.0 55 | 56 | - Migrate to imports via clojure compatible `ns` form instead custom 57 | `import` forms used previously. 58 | - Factor out interactive try tool into seperate project: 59 | https://github.com/Gozala/try-wisp 60 | 61 | ## 0.6.7 62 | 63 | - Implement `repeat` function that is similar to clojure's but 64 | is not lazy and only supports finite options. 65 | - Implement `(print foo bar)` function & macro that serves as a 66 | shortcut for `(.log console foo bar)`. 67 | - Implement `ns` macro that implements subset of clojure's `ns` that 68 | compiles to plain requires. For now only few types of requirement 69 | declarations are recognized and compiled to `require` calls. 70 | - `(:require module.name)` 71 | - `(:require lib.foo :as foo)` 72 | - `(:use wisp.sequence :only [first second])` 73 | - `(:use wisp.sequence :rename {first car rest cdr}) 74 | Relative requires forms are produced by resolving requirements to 75 | a defined ns name. If requirement does not shares root of ns name 76 | then absolute require forms are generated. 77 | - Update travis-ci config to test on later node versions. 78 | 79 | ## 0.6.6 80 | 81 | - Fix indentation in compile output to avoid trailing white-spaces. 82 | - Fix compile output for `get` special form to allow `nil` as first 83 | argument and add fallback argument support. 84 | - Stop tracking compiled JS in git. 85 | - Change file layout to allow loading of core modules like: `wisp/runtime`. 86 | 87 | ## 0.6.5 88 | 89 | - Implement `identity` function. 90 | - Factor out parts of `compiler` into backend specific `writer`. 91 | - Implement `seq?` function. 92 | - Implement `take-while` function. 93 | - Various code maintainibily improvements. 94 | - Add `read*` function for reading out multiple forms. 95 | - Add `compile*` function for complining multiple forms. 96 | 97 | ## 0.6.4 98 | 99 | - Fix regression in REPL. 100 | - Change reader such that no unread is necessary. 101 | - Fix metadata mixup in multiline forms. 102 | 103 | ## 0.6.3 104 | 105 | - Fix bugs introduced by 0.6.1 and re-release. 106 | 107 | ## 0.6.2 108 | 109 | - Revert back to 0.6.0 as builds were broken. 110 | 111 | ## 0.6.1 112 | 113 | - Remove obsolete `exprots` form in favor of 114 | implicit exports. 115 | 116 | ## 0.6.0 117 | 118 | - Add support for `()` form as a sugar to `'()` 119 | - Improve REPL support for multi-line inputs. 120 | - Add `*debug*` setting to REPL to print intermediate forms. 121 | - Allow access to last 3 forms read in REPL from `**1`, `**2`, `**3`. 122 | - Allow access to last 3 evalution result in REPL as `*1`, `*2` `*3`. 123 | - Make wisp types more tolarant to multiple JS contexts. 124 | - Fix bug in `(get (or a b) c)` like forms. 125 | - Make `(:foo bar)` compatible with `nil` `bar` values. 126 | - Export all the top level definitions unless marked as private. 127 | - Implement `defn-` macro for defining private functions. 128 | - Implement `str` macro in order to inline common cases. 129 | - Fix keyword based metadata sugar `(^:foo bar) ;; => (with-meta bar {:foo true})`. 130 | - Improvements to `assert` macro. 131 | - Reader simplifications. 132 | 133 | ## 0.5.0 134 | 135 | - Improved REPL prints lisp forms instead of JS. 136 | - Implement `pr-str` function from clojure. 137 | - Symbols now obtain take metadata. 138 | 139 | ## 0.4.1 140 | 141 | - Fix regressions introduced in 4.0.0 142 | - Rewrite function compiler to depend less on symbol implementation details. 143 | 144 | ## 0.4.0 145 | 146 | - Compile symbols to function calls `'foo => (symbol nil "foo")`. 147 | - Covert `=` special form to clojure compliant function. 148 | 149 | ## 0.3.3 150 | 151 | - Implement runtime equivalents of `= == + - / * > >= < <=` special forms. 152 | - Implement runtime equivalents of `and or` special forms. 153 | 154 | ## 0.3.2 155 | 156 | - Hotfix `(/ a b)` special forms. 157 | 158 | ## 0.3.1 159 | 160 | - Fix the way `/` symbols are handled. 161 | 162 | ## 0.3.0 163 | 164 | - Initial support for lazy sequences. 165 | - Improve conventional name translation to handle `+ - / * > < >= <=` better. 166 | - Minor bug fixes. 167 | 168 | ## 0.2.0 169 | 170 | - Add short anonymous function literal support. 171 | - Fix regex with `/` chars. 172 | - Add line and column information to the metadata. 173 | - Reader code cleanup. 174 | 175 | ## 0.1.2 176 | 177 | - Remove backend specific forms like `.concat`, `.indexOf`, etc form 178 | reader and compiler. 179 | 180 | ## 0.1.1 181 | 182 | - Implement string module. 183 | - Minor enhancements to runtime type check functions. 184 | - Cleanup modules from JS specific calls. 185 | 186 | ## 0.1.0 187 | 188 | - Implement type agnostic sequence module. 189 | 190 | ## 0.0.3 191 | 192 | - Fix typos in introduction code. 193 | 194 | ## 0.0.2 195 | 196 | 197 | - Compiler simplifications 198 | - Switch to literal forms of array, hash, symbols now that new compiler 199 | supports them. 200 | - Improve internal macro system to allow `fn` installations as macros. 201 | - Implement built-in macros as functions. 202 | - Implement `apply` special form. 203 | - Fix `concat-list` to support multiple unquote-splicings in a list. 204 | - Implement function overload on arity. 205 | - Implement generic sequence functions in a sequence module. 206 | - Write wisp introduction guide. 207 | 208 | ## 0.0.1 209 | 210 | - Initial release 211 | -------------------------------------------------------------------------------- /resources/wisp/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Irakli Gozalishvili 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of Irakli Gozalishvili nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /resources/wisp/Makefile: -------------------------------------------------------------------------------- 1 | BROWSERIFY = ./node_modules/browserify/bin/cmd.js 2 | MINIFY = ./node_modules/.bin/minify 3 | WIPS_CURRENT = node ./bin/wisp.js 4 | FLAGS = 5 | INSTALL_MESSAGE = "You need to run 'npm install' to install build dependencies." 6 | BUILD_DEPS = $(BROWSERIFY) $(MINIFY) ./node_modules/wisp/bin/wisp.js 7 | # set make's source file search path 8 | vpath % src 9 | 10 | ifdef verbose 11 | FLAGS = --verbose 12 | endif 13 | 14 | ifdef current 15 | WISP = $(WIPS_CURRENT) 16 | else 17 | WISP = ./node_modules/wisp/bin/wisp.js 18 | endif 19 | 20 | core: runtime sequence string ast reader compiler writer analyzer expander escodegen 21 | escodegen: escodegen-writer escodegen-generator 22 | node: core wisp node-engine repl 23 | browser: core browser-engine dist/wisp.min.js 24 | compiler: core browser-engine dist/wispcompiler.min.js 25 | all: node browser 26 | test: test1 27 | 28 | test1: core node 29 | $(WIPS_CURRENT) ./test/test.wisp $(FLAGS) 30 | 31 | $(BUILD_DEPS): 32 | @echo $(INSTALL_MESSAGE) 33 | @exit 1 34 | 35 | clean: 36 | rm -rf engine 37 | rm -rf backend 38 | rm -rf dist 39 | rm -f *.js 40 | 41 | %.js: %.wisp $(WISP) 42 | @mkdir -p $(dir $@) 43 | $(WISP) --source-uri wisp/$(subst .js,.wisp,$@) < $< > $@ 44 | 45 | ### core ### 46 | 47 | repl: repl.js 48 | 49 | reader: reader.js 50 | 51 | compiler: compiler.js 52 | 53 | runtime: runtime.js 54 | 55 | sequence: sequence.js 56 | 57 | string: string.js 58 | 59 | ast: ast.js 60 | 61 | analyzer: analyzer.js 62 | 63 | expander: expander.js 64 | 65 | wisp: wisp.js 66 | 67 | writer: backend/javascript/writer.js 68 | 69 | ### escodegen backend ### 70 | 71 | escodegen-writer: backend/escodegen/writer.js 72 | 73 | escodegen-compiler: backend/escodegen/compiler.js 74 | 75 | escodegen-generator: backend/escodegen/generator.js 76 | 77 | ### platform engine bundles ### 78 | 79 | node-engine: ./engine/node.js 80 | 81 | browser-engine: ./engine/browser.js 82 | browser-compiler-engine: ./engine/browserCompiler.js 83 | 84 | dist/wisp.js: engine/browser.js $(WISP) $(BROWSERIFY) core 85 | @mkdir -p dist 86 | $(BROWSERIFY) --debug --exports require --entry engine/browser.js > dist/wisp.js 87 | 88 | dist/wisp.min.js: dist/wisp.js $(MINIFY) 89 | @mkdir -p dist 90 | $(MINIFY) dist/wisp.js > dist/wisp.min.js 91 | 92 | dist/wispcompiler.js: engine/browserCompiler.js $(WISP) $(BROWSERIFY) core 93 | @mkdir -p dist 94 | $(BROWSERIFY) --debug --exports require --entry engine/browserCompiler.js -t brfs > dist/wispcompiler.js 95 | 96 | dist/wispcompiler.min.js: dist/wispcompiler.js $(MINIFY) 97 | @mkdir -p dist 98 | $(MINIFY) dist/wispcompiler.js > dist/wispcompiler.min.js 99 | -------------------------------------------------------------------------------- /resources/wisp/README.md: -------------------------------------------------------------------------------- 1 | A little Clojure-like LISP in JavaScript. 2 | 3 | 4 | 5 | 1. Read about the [language essentials & documentation](./doc/language-essentials.md). 6 | 7 | 2. Drop [wisp.min.js](https://github.com/Gozala/wisp/raw/gh-pages/dist/wisp.min.js) into your HTML code: 8 | 9 | ```html 10 | 11 | 12 | 15 | 16 | 17 | 18 | ``` 19 | 20 | 3. Or install the binary with npm: 21 | 22 | `npm install wisp` 23 | 24 | 4. Compile wisp code to native JS just like CoffeeScript: 25 | 26 | `node_modules/.bin/wisp < my-script.wisp > my-script.js` 27 | 28 | 5. Fire up a REPL to explore the language: 29 | 30 | `./node_modules/.bin/wisp` 31 | 32 | [More info](./doc/more-info.md). 33 | 34 | Wisp is currently in maintenance mode. We're merging PRs but not actively writing new code. 35 | -------------------------------------------------------------------------------- /resources/wisp/doc/language-essentials.md: -------------------------------------------------------------------------------- 1 | # Language Essentials 2 | 3 | ## Data structures 4 | 5 | 6 | #### nil 7 | 8 | `nil` is just like JavaScript `undefined` with the difference that it 9 | cannot be redefined. It compiles down to `void(0)` in JavaScript. 10 | 11 | ```clojure 12 | nil ; => void(0) 13 | ``` 14 | 15 | #### Booleans 16 | 17 | `true` / `false` are directly equivalent to plain JavaScript booleans: 18 | 19 | ```clojure 20 | true ; => true 21 | ``` 22 | 23 | #### Numbers 24 | 25 | _wisp_ numbers are directly equivalent to JavaScript numbers: 26 | 27 | ```clojure 28 | 1 ; => 1 29 | ``` 30 | 31 | #### Strings 32 | 33 | _wisp_ strings are JavaScript strings: 34 | 35 | ```clojure 36 | "Hello world" 37 | ``` 38 | ...and can be multi-line: 39 | 40 | ```clojure 41 | "Hello, 42 | My name is wisp!" 43 | ``` 44 | 45 | #### Characters 46 | 47 | Characters are syntactic sugar for single character strings: 48 | 49 | ```clojure 50 | \a ; => "a" 51 | \b ; => "b" 52 | ``` 53 | 54 | #### Keywords 55 | Keywords are symbolic identifiers that evaluate to themselves: 56 | 57 | ```clojure 58 | :keyword ; => "keyword" 59 | ``` 60 | 61 | Since in JavaScript string constants fulfill the purpose of symbolic identifiers, 62 | keywords compile to equivalent strings in JavaScript. This allows using 63 | keywords in Clojure(Script) and JavaScript idiomatic fashion: 64 | 65 | ```clojure 66 | (window.addEventListener :load handler false) 67 | ``` 68 | 69 | Keywords can also be invoked as functions, although that too is syntax sugar 70 | that compiles to property access in JavaScript: 71 | 72 | ```clojure 73 | (:bar foo) ; => (foo || 0)["bar"] 74 | ``` 75 | 76 | Note that keywords in _wisp_ are not real functions so they can't be composed 77 | or passed to high order functions. 78 | 79 | #### Vectors 80 | 81 | _wisp_ vectors are plain JavaScript arrays, but nevertheless all standard 82 | library functions are non-destructive and pure functional as in Clojure. 83 | 84 | ```clojure 85 | [ 1 2 3 4 ] 86 | ``` 87 | Note: Commas are considered whitespace and can be used if desired: 88 | 89 | ```clojure 90 | [1, 2, 3, 4] 91 | ``` 92 | #### Dictionaries 93 | 94 | _wisp_ does not have Clojure-like value-to-value maps by default, but rather dictionaries that map to plain JavaScript objects. 95 | 96 | Therefore, unlike Clojure, keys cannot consist of arbitrary types. 97 | 98 | ```clojure 99 | { "foo" bar :beep-bop "bop" 1 2 } 100 | ``` 101 | Like with vectors, commas are optional but can come handy for separating key value pairs. 102 | 103 | ```clojure 104 | { :a 1, :b 2 } 105 | ``` 106 | 107 | #### Lists 108 | 109 | What would be a LISP without lists? _wisp_ being homoiconic, its 110 | code is made up of lists representing expressions. 111 | 112 | As in other LISPs, the first item of an expression is an operator or function that takes the remainder of the list as arguments, and compiles accordingly to JavaScript: 113 | 114 | 115 | ```clojure 116 | (foo bar baz) ; => foo(bar, baz); 117 | ``` 118 | 119 | The compiled JavaScript is quite unlikely to end up with lists as they primarily serve their purpose at compile time. Nevertheless lists are supported and can be used (more further down) 120 | 121 | #### Arrays 122 | 123 | _wisp_ partially emulates Clojure(Script) handling of arrays in two ways: 124 | 125 | 1. By using `get`, which compiles to guarded access in JavaScript: 126 | 127 | ```clojure 128 | (get [1 2 3] 1) ; => ([1, 2, 3] || 0)[0] 129 | ``` 130 | 131 | 2. By using `aget`, which compiles to unguarded access and can (for the moment) also be used to perform item assignments: 132 | 133 | ```clojure 134 | (aget an-array 2) ; => anArray[2]; 135 | (set! (aget an-array 2) "bar") ; => anArray[2] = "bar"; 136 | ``` 137 | 138 | (`aset` will be added ASAP for symmetry, but you can easily define an equivalent macro for the moment) 139 | 140 | ## Conventions 141 | 142 | _wisp_ tries very hard to compile to JavaScript that feels hand-crafted while trying to embrace LISP-style idioms and naming conventions, and translates them to equivalent JavaScript conventions: 143 | 144 | ```clojure 145 | (dash-delimited) ; => dashDelimited 146 | (predicate?) ; => isPredicate 147 | (**privates**) ; => __privates__ 148 | (list->vector) ; => listToVector 149 | ``` 150 | 151 | This makes for very natural-looking code, but also allows some things to be expressed in different ways. For instance, the following function invocations will translate to the same things: 152 | 153 | ```clojure 154 | (parse-int x) 155 | (parseInt x) 156 | 157 | (array? x) 158 | (isArray x) 159 | ``` 160 | 161 | 162 | ## Special forms 163 | 164 | There are some special operators in _wisp_ in the sense that 165 | they compile to JavaScript expressions rather then function calls. 166 | 167 | Identically-named functions are also available in the standard library to allow function composition. 168 | 169 | #### Arithmetic operations 170 | 171 | _wisp_ comes with special forms for common arithmetic: 172 | 173 | ```clojure 174 | (+ a b) ; => a + b 175 | (+ a b c) ; => a + b + c 176 | (- a b) ; => a - b 177 | (* a b c) ; => a * b * c 178 | (/ a b) ; => a / b 179 | (mod a b) ; => a % 2 180 | ``` 181 | 182 | #### Comparison operations 183 | 184 | ...and special forms for common comparisons: 185 | 186 | ```clojure 187 | (identical? a b) ; => a === b 188 | (identical? a b c) ; => a === b && b === c 189 | (= a b) ; => a == b 190 | (= a b c) ; => a == b && b == c 191 | (> a b) ; => a > b 192 | (>= a b) ; => a >= b 193 | (< a b c) ; => a < b && b < c 194 | (<= a b c) ; => a <= b && b <= c 195 | ``` 196 | 197 | #### Logical and bitwise operations 198 | 199 | ...and special forms for logical and bitwise operations: 200 | 201 | ```clojure 202 | (and a b) ; => a && b 203 | (and a b c) ; => a && b && c 204 | (or a b) ; => a || b 205 | (and (or a b) 206 | (and c d)) ; (a || b) && (c && d) 207 | ``` 208 | 209 | ```clojure 210 | (bit-and a b) ; => a & b 211 | (bit-or a b) ; => a | b 212 | (bit-xor a b) ; => a ^ b 213 | (bit-shift-left a 2) ; => a << 2 214 | (bit-shift-right b 3) ; => b >> 3 215 | (bit-shift-right-zero-fil a 1) ; => a >>> 1 216 | ``` 217 | 218 | #### Definitions 219 | 220 | Variable definitions also happen through special forms: 221 | 222 | ```clojure 223 | (def a) ; => var a = void(0); 224 | (def b 2) ; => var b = 2; 225 | ``` 226 | 227 | #### Assignments 228 | 229 | In _wisp_ variables can be set to new values via the `set!` special form. 230 | 231 | Note that in functional programing binding changes are a bad practice (avoiding these will improve the quality and testability of your code), but there are always cases where this is required for JavaScript interoperability: 232 | 233 | ```clojure 234 | (set! a 1) ; => a = 1 235 | ``` 236 | The `!` suffix is a useful visual reminder that you're causing a side-effect. 237 | 238 | #### Conditionals 239 | 240 | Conditional code branching in _wisp_ is expressed via the `ìf` special form. 241 | 242 | As usual, the first expression following `if` is a condition - if it evaluates to `true` the result of the `if` form will be the second expression, otherwise it'll be the third "else" expression: 243 | 244 | ```clojure 245 | (if (< number 10) 246 | "Digit" 247 | "Number") 248 | ``` 249 | 250 | The third ("else") expression is optional, and if missing and the conditional evaluates to `true` the result will be `nil`. 251 | 252 | ```clojure 253 | (if (monday? today) "How was your weekend") 254 | ``` 255 | 256 | The form `cond` is also available: 257 | 258 | ```clojure 259 | (cond 260 | (monday? today) "How was your weekend" 261 | (friday? today) "Enjoy your weekend" 262 | (weekend? today) "Huzzah weekend" 263 | :else "Some other day") 264 | ``` 265 | 266 | Each term is evaluated in sequence until it evaluates to true. If none are true, 267 | the form evaluates to `undefined`. 268 | 269 | #### Combining expressions 270 | 271 | In _wisp_ everything is an expression, but sometimes one might want to combine multiple expressions into one, usually for the purpose of evaluating expressions that have side-effects. That's where `do` comes in: 272 | 273 | ```clojure 274 | (do 275 | (console.log "Computing sum of a & b") 276 | (+ a b)) 277 | ``` 278 | 279 | `do` can take any number of expressions (including `0`, in which case it will evaluate to `nil`): 280 | 281 | ```clojure 282 | (do) ; => nil 283 | ``` 284 | 285 | #### Bindings 286 | 287 | The `let` special form evaluates sub-expressions in a lexical context in which symbols in its binding-forms (first item) are bound to their respective expression results: 288 | 289 | ```clojure 290 | (let [a 1 291 | b (+ a 1)] 292 | (+ a b)) 293 | ; => 3 294 | ``` 295 | 296 | 297 | #### Functions 298 | 299 | _wisp_ functions are plain JavaScript functions 300 | 301 | ```clojure 302 | (fn [x] (+ x 1)) ; => function(x) { return x + 1; } 303 | ``` 304 | 305 | _wisp_ functions can have names, just as in JavaScript 306 | 307 | ```clojure 308 | (fn increment [x] (+ x 1)) ; => function increment(x) { return x + 1; } 309 | ``` 310 | 311 | _wisp_ function _declarations_ can also contain documentation and some metadata: 312 | 313 | ```clojure 314 | (defn sum 315 | "Return the sum of all arguments" 316 | {:version "1.0"} 317 | [x] (+ x 1)) 318 | ``` 319 | 320 | Function _expressions, though, can only have names: 321 | 322 | ```clojure 323 | (fn increment 324 | {:added "1.0"} 325 | [x] (+ x 1)) 326 | ``` 327 | 328 | _Note: Docstrings and metadata are not included in compiled JavaScript yet, but support for that is planned._ 329 | 330 | #### Arguments 331 | 332 | _wisp_ makes capturing of remaining (`rest`) arguments a lot easier than JavaScript. An argument that follows an ampersand (`&`) symbol will capture the remaining args in a standard vector (i.e., array). 333 | 334 | ```clojure 335 | (fn [x & rest] 336 | (rest.reduce (fn [sum x] (+ sum x)) x)) 337 | ``` 338 | 339 | #### Overloading Functions 340 | 341 | In _wisp_ functions can be overloaded depending on arity (the number of arguments they take), without introspection of remaining arguments. 342 | 343 | ```clojure 344 | (fn sum 345 | "Return the sum of all arguments" 346 | {:version "1.0"} 347 | ([] 0) 348 | ([x] x) 349 | ([x y] (+ x y)) 350 | ([x & more] (more.reduce (fn [x y] (+ x y)) x))) 351 | ``` 352 | 353 | If a function does not have variadic overload and more arguments are passed to it, it throws an exception. 354 | 355 | ```clojure 356 | (fn 357 | ([x] x) 358 | ([x y] (- x y))) 359 | ``` 360 | 361 | #### Loops and TCO 362 | 363 | A classic way to build a loop in LISP is via recursion, _wisp_ provides a `loop` `recur` construct that allows for tail call optimization: 364 | 365 | ```clojure 366 | (loop [x 10] 367 | (if (> x 1) 368 | (print x) 369 | (recur (- x 2)))) 370 | ``` 371 | 372 | ## Other Special Forms 373 | 374 | ### Instantiation 375 | 376 | In _wisp_ type instantiation has a concise form, by way of suffixing the function with a period (`.`): 377 | 378 | ```clojure 379 | (Type. options) 380 | ``` 381 | 382 | However, the more verbose but more JavaScript-like form is also valid: 383 | 384 | ```clojure 385 | (new Class options) 386 | ``` 387 | 388 | #### Method calls 389 | 390 | In _wisp_ method calls are no different from function calls, but prefixed with a period (`.`): 391 | 392 | ```clojure 393 | (.log console "hello wisp") 394 | ``` 395 | 396 | ...and, of course, the more JavaScript-like forms are supported too: 397 | 398 | ```clojure 399 | (window.addEventListener "load" handler false) 400 | ``` 401 | 402 | #### Attribute access 403 | 404 | In _wisp_, attribute access is also treated like a function call, but attributes need to be prefixed with `.-`: 405 | 406 | ```clojure 407 | (.-location window) 408 | ``` 409 | 410 | Compound properties can be accessed via the `get` special form: 411 | 412 | ```clojure 413 | (get templates (.-id element)) 414 | ``` 415 | 416 | #### Catching Exceptions 417 | 418 | In _wisp_ exceptions can be handled via the `try` special form. As with everything 419 | else, the `try` form is also an expression that evaluates to `nil` if no handling 420 | takes place. 421 | 422 | ```clojure 423 | (try (raise exception)) 424 | ``` 425 | 426 | ...the `catch` form can be used to handle exceptions... 427 | 428 | ```clojure 429 | (try 430 | (raise exception) 431 | (catch error (.log console error))) 432 | ``` 433 | 434 | ...and the `finally` clause can be used too: 435 | 436 | ```clojure 437 | (try 438 | (raise exception) 439 | (catch error (recover error)) 440 | (finally (.log console "That was a close one!"))) 441 | ``` 442 | 443 | 444 | #### Throwing Exceptions 445 | 446 | In a non-idiomatic twist (but largely for symmetry and JavaScript interop), the `throw` special form allows throwing exceptions: 447 | 448 | ```clojure 449 | (fn raise [message] (throw (Error. message))) 450 | ``` 451 | 452 | ## Macros 453 | 454 | _wisp_ has a powerful programmatic macro system which allows the compiler to 455 | be extended by user code. 456 | 457 | Many core constructs of _wisp_ are in fact normal macros, and you are encouraged to study the source to learn how to build your own. Nevertheless, the following sections are a quick primer on macros. 458 | 459 | #### quote 460 | 461 | Before diving into macros too much, we need to learn a few more 462 | things. In LISP any expression can be quoted to prevent it from being 463 | evaluated. 464 | 465 | As an example, take the symbol `foo` - by default, you will be 466 | evaluating the reference to its corresponding value: 467 | 468 | ```clojure 469 | foo 470 | ``` 471 | 472 | But if you wish to refer to the literal symbol, this is how you do it: 473 | 474 | ```clojure 475 | (quote foo) 476 | ``` 477 | 478 | or, as shorthand: 479 | 480 | ```clojure 481 | 'foo 482 | ``` 483 | 484 | Any expression can be quoted to prevent its evaluation (these are not, however, compiled to JavaScript): 485 | 486 | ```clojure 487 | 'foo 488 | ':bar 489 | '(a b) 490 | ``` 491 | 492 | #### An Example Macro 493 | 494 | _wisp_ doesn't have the `unless` special form or a macro, but it's trivial 495 | to implement it via macros. 496 | 497 | But it's useful to try implementing it as a function to understand a use case for macros, so let's get started: 498 | 499 | `unless` is easy to understand -- we want to execute a `body` unless a given `condition` is `true`: 500 | 501 | ```clojure 502 | (defn unless-fn [condition body] 503 | (if condition nil body)) 504 | ``` 505 | 506 | But since function arguments are evaluated before the function itself is called, the following code will _always_ write a log message: 507 | 508 | ```clojure 509 | (unless-fn true (console.log "should not print")) 510 | ``` 511 | 512 | Macros solve this problem, because they do not evaluate their arguments 513 | immediately. Instead, you get to choose when (and if!) the arguments 514 | to a macro are evaluated. Macros take items of the expression as 515 | arguments and return a new form that is compiled instead. 516 | 517 | ```clojure 518 | (defmacro unless 519 | [condition form] 520 | (list 'if condition nil form)) 521 | ``` 522 | 523 | The body of the `unless` macro executes at macro expansion time, producing an `if` 524 | form for compilation. This way the compiled JavaScript is a conditional instead of a function call. 525 | 526 | ```clojure 527 | (unless true (console.log "should not print")) 528 | ``` 529 | 530 | #### syntax-quote 531 | 532 | Simple macros like the above could be written via templating and expressed 533 | as syntax-quoted forms. 534 | 535 | `syntax-quote` is almost the same as plain `quote`, but it allows 536 | sub expressions to be unquoted so that form acts as a template. 537 | 538 | The symbols inside the form are resolved to help prevent inadvertent symbol capture, which can be done via `unquote` and `unquote-splicing` forms. 539 | 540 | ```clojure 541 | (syntax-quote (foo (unquote bar))) 542 | (syntax-quote (foo (unquote bar) (unquote-splicing bazs))) 543 | ``` 544 | 545 | Note that there is special syntactic sugar for both unquoting operators: 546 | 547 | 1. Syntax quote: Quote the form, but allow internal unquoting so that the form acts 548 | as template. Symbols inside the form are resolved to help prevent inadvertent symbol 549 | capture. 550 | 551 | ```clojure 552 | `(foo bar) 553 | ``` 554 | 555 | 2. Unquote: Use inside a syntax-quote to substitute an unquoted value. 556 | 557 | ```clojure 558 | `(foo ~bar) 559 | ``` 560 | 561 | 3. Splicing unquote: Use inside a syntax-quote to splice an unquoted 562 | list into a template. 563 | 564 | ```clojure 565 | `(foo ~bar ~@bazs) 566 | ``` 567 | 568 | For example, the built-in `defn` macro can be defined with a simple 569 | template macro. That's more or less how the built-in `defn` macro is implemented. 570 | 571 | ```clojure 572 | (defmacro define-fn 573 | [name & body] 574 | `(def ~name (fn ~@body))) 575 | ``` 576 | 577 | Now if we use `define-fn` form above, the defined macro will be expanded 578 | at compile time, resulting into different program output. 579 | 580 | ```clojure 581 | (define-fn print 582 | [message] 583 | (.log console message)) 584 | ``` 585 | 586 | Not all of the macros can be expressed via templating, but all of the 587 | language is available to assemble macro expanded forms. 588 | 589 | #### Another Macro Example 590 | 591 | As an example, let's define a macro to ease functional chaining, a technique popular 592 | in JavaScript but usually expressed via method chaining. A typical use of that would be something like: 593 | 594 | ```javascript 595 | open(target, "keypress"). 596 | filter(isEnterKey). 597 | map(getInputText). 598 | reduce(render) 599 | ``` 600 | 601 | Unfortunately, though, it usually requires that all the chained functions need to be methods of an object, which is very limited and has the undesirable effect of making third party functions "second class". 602 | 603 | But using macros we can achieve similar chaining without such tradeoffs, and chain _any_ function: 604 | 605 | ```clojure 606 | (defmacro -> 607 | [& operations] 608 | (reduce 609 | (fn [form operation] 610 | (cons (first operation) 611 | (cons form (rest operation)))) 612 | (first operations) 613 | (rest operations))) 614 | 615 | (-> 616 | (open target :keypress) 617 | (filter enter-key?) 618 | (map get-input-text) 619 | (reduce render)) 620 | ``` 621 | 622 | ## Import/Export (Symbols and Modules) 623 | 624 | ### Exporting Symbols 625 | 626 | All the top level definitions in a file are exported by default: 627 | 628 | ```clojure 629 | (def foo bar) 630 | (defn greet [name] (str "hello " name)) 631 | ``` 632 | 633 | ...but it's still possible to define top level bindings without exporting them via `^:private` metadata: 634 | 635 | ```clojure 636 | (def ^:private foo bar) 637 | ``` 638 | 639 | ...and a little syntax sugar for functions: 640 | 641 | ```clojure 642 | (defn- greet [name] (str "hello " name)) 643 | ``` 644 | 645 | 646 | ### Importing 647 | 648 | Module importing is done via an `ns` special form that is manually 649 | named. Unlike `ns` in Clojure(Script), _wisp_ takes a minimalistic 650 | approach and supports only one essential way of importing modules: 651 | 652 | ```clojure 653 | (ns interactivate.core.main 654 | "interactive code editing" 655 | (:require [interactivate.host :refer [start-host!]] 656 | [fs] 657 | [wisp.backend.javascript.writer :as writer] 658 | [wisp.sequence 659 | :refer [first rest] 660 | :rename {first car rest cdr}])) 661 | ``` 662 | 663 | Let's go through the above example to get a complete picture regarding 664 | how modules can be imported: 665 | 666 | 1. The first parameter `interactivate.core.main` is a name of the 667 | module / namespace. In this case it represents module 668 | `./core/main` under the package `interactivate`. While this is 669 | not enforced in any way the common convention is that these mirror the filesystem hierarchy. 670 | 671 | 2. The second string parameter is just a description of the module 672 | and is completely optional. 673 | 674 | 3. The `(:require ...)` form defines dependencies that will be 675 | imported at runtime, and the example above imports multiple modules: 676 | 677 | 1. First it imports the `start-host!` function from the 678 | `interactivate.host` module. That will be loaded from the 679 | `../host` location, since because module paths are resolved 680 | relative to a name, but only if they share the same root. 681 | 2. The second form imports `fs` module and makes it available under 682 | the same name. Note that in this case it could have been 683 | written without wrapping it in brackets. 684 | 3. The third form imports `wisp.backend.javascript.writer` module 685 | from `wisp/backend/javascript/writer` and makes it available 686 | via the name `writer`. 687 | 4. The last and most complex form imports `first` and `rest` 688 | functions from the `wisp.sequence` module, although it also 689 | renames them and there for makes available under different 690 | `car` and `cdr` names. 691 | 692 | While Clojure has many other kinds of reference forms they are 693 | not recognized by _wisp_ and will therefore be ignored. 694 | 695 | ### Types and Protocols 696 | 697 | In wisp protocols can be defined same as in Clojure(Script), 698 | via [defprotocol](http://clojuredocs.org/clojure_core/clojure.core/defprotocol): 699 | 700 | ```clojure 701 | (defprotocol ISeq 702 | (-first [coll]) 703 | (-rest [coll])) 704 | 705 | (defprotocol ICounted 706 | (^number count [coll] "constant time count")) 707 | ``` 708 | 709 | Above code will define `ISeq`, `ICounted` protocols (objects representing 710 | those protocol) and `_first`, `_rest`, `count` functions, that dispatch on 711 | first argument (that must implement associated protocol). 712 | 713 | 714 | Existing types / classes (defined either in wisp or JS) can be 715 | extended to implement specific protocol using 716 | [extend-type](http://clojuredocs.org/clojure_core/clojure.core/extend-type): 717 | 718 | ```clojure 719 | (extend-type Array 720 | ICounted 721 | (count [array] (.-length array)) 722 | ISeq 723 | (-first [array] (aget array 0)) 724 | (-rest [array] (.slice array 1))) 725 | ``` 726 | 727 | Once type / class implemnets some protocol, it's functions can be used 728 | on the instances of that type / class. 729 | 730 | ```clojure 731 | (count []) ;; => 0 732 | (count [1 2]) ;; => 2 733 | (-first [1 2 3]) ;; => 1 734 | (-rest [1 2 3]) ;; => [2 3] 735 | ``` 736 | 737 | In wisp value can be checked to satisfy given protocol same as in 738 | Clojure(Script) via [satisfies?](http://clojuredocs.org/clojure_core/clojure.core/satisfies_q): 739 | 740 | ```clojure 741 | (satisfies? ICounted [1 2]) 742 | (satisfies? ISeq []) 743 | ``` 744 | 745 | New types (that translate to JS classes) can be defined same as in 746 | Clojure(Script) via [deftype](http://clojuredocs.org/clojure_core/clojure.core/deftype) 747 | form: 748 | 749 | ```clojure 750 | (deftype List [head tail size] 751 | ICounted 752 | (count [_] size) 753 | ISeq 754 | (-first [_] head) 755 | (-rest [_] tail) 756 | Object 757 | (toString [self] (str "(" (join " " self) ")"))) 758 | ``` 759 | 760 | Note: Protocol functions are defined as methods with unique names 761 | (that include namespace info where protocol was defined, protocol 762 | name & method name) to avoid name collisions on types / classes 763 | implementing them. This implies that such methods aren't very 764 | useful from JS side. Special `Object` protocol can be used to 765 | define methods who's names will be kept as is, which can be used 766 | to define interface to be used from JS side (like `toString` 767 | method above). 768 | 769 | In wisp multiple types can be extended to implement a specific 770 | protocol using [extend-protocol](http://clojuredocs.org/clojure_core/clojure.core/extend-protocol) 771 | form same as in Clojure(Script) too. 772 | 773 | [homoiconicity]:http://en.wikipedia.org/wiki/Homoiconicity 774 | [clojure]:http://clojure.org/ 775 | [macros]:http://clojure.org/macros 776 | [s-expressions]:http://en.wikipedia.org/wiki/S-expression 777 | [clojurescript]:https://github.com/clojure/clojurescript 778 | [markdown]:http://daringfireball.net/projects/markdown/ 779 | -------------------------------------------------------------------------------- /resources/wisp/doc/more-info.md: -------------------------------------------------------------------------------- 1 | Wisp is a homoiconic JavaScript dialect with Clojure syntax, s-expressions and macros. 2 | 3 | [Language essentials & documentation](./language-essentials.md). 4 | 5 | Think of wisp as markdown for JavaScript programming, but with the added subtlety of LISP S-expressions, homoiconicity and powerful macros that make it the easiest way to write JavaScript. 6 | 7 | *Why wouldn't I just use ClojureScript?* 8 | 9 | For 99% of use-cases you probably should just use ClojureScript. 10 | 11 | However, here are some niches that wisp might fill: 12 | 13 | * Compiles down to readable JavaScript. 14 | * No complicated stack or setup - contributors only need a browser. 15 | * Including it in a project can be as simple as a single `