{ "name": "wisp", "id": "wisp", "version": "0.6.7", "description": "Homoiconic JS with clojure syntax, s-expressions & macros", "author": { "name": "Irakli Gozalishvili", "email": "rfobic@gmail.com", "url": "http://jeditoolkit.com" }, "homepage": "https://github.com/Gozala/wisp", "keywords": [ "compiler", "language", "transpiler", "javascript", "lisp", "clojure", "maros", "s-expression", "homoiconicity", "functional" ], "repository": { "type": "git", "url": "https://github.com/Gozala/wisp.git", "web": "https://github.com/Gozala/wisp" }, "bugs": { "url": "https://github.com/Gozala/wisp/issues/" }, "licenses": [ { "type": "BSD New", "url": "http://opensource.org/licenses/BSD-3-Clause" } ], "devDependencies": { "browserify": "2.14.1", "wisp": "0.6.6" }, "engines": { "node": ">=0.4.0" }, "main": "./wisp.js", "bin": { "wisp": "./bin/wisp.js" }, "scripts": { "prepublish": "make all", "test": "make all && make test" }, "readme": "# Wisp\n\nWisp is a [homoiconic][homoiconicity] JavaScript dialect with [clojure] syntax,\n[s-expressions] and [macros]. Unlike [clojurescript], Wisp code compiles to\nhuman-readable JavaScript. The goal of Wisp is to compile to the JavaScript\nyou would have written anyway. Think of Wisp as [markdown] for JS programing!\n\n[Homoiconic][homoiconicity] syntax and [macros] are the primary motivations!\n\n![meta](http://upload.wikimedia.org/wikipedia/en/b/ba/DrawingHands.jpg)\n\n# Try\n\nYou can try it before you buy it:\nhttp://jeditoolkit.com/wisp/\n\n# Install\n\n npm install -g wisp\n\n[![Build Status](https://secure.travis-ci.org/Gozala/wisp.png)](http://travis-ci.org/Gozala/wisp)\n\n\n# Introduction\n\n\nWisp is homoiconic JS dialect with a clojure syntax, s-expressions and\nmacros. Wisp code compiles to a human readable javascript, which is one\nof they key differences from clojurescript.\n\n\n## Data structures\n\n\n\n#### nil\n\n`nil` is just like JS `undefined` with a difference that it\ncannot be redefined. It's just a shortcut for `void(0)` in JS.\n\n```clojure\nnil ;; => void(0)\n```\n\n#### Booleans\n\nWisp booleans `true` / `false` are plain JS booleans.\n\n```clojure\ntrue ;; => true\n```\n\n#### Numbers\n\nWisp numbers are JS numbers\n\n```clojure\n1 ;; => 1\n```\n\n#### Strings\n\nWisp strings are JS Strings\n\n```clojure\n\"Hello world\"\n```\n\nWisp strings can be multiline\n\n```clojure\n\"Hello,\nMy name is wisp!\"\n```\n\n#### Characters\n\nCharacters are syntatic sugar for JS single char strings\n\n```clojure\n\\a ;; => \"a\"\n\\b ;; => \"b\"\n```\n\n#### Keywords\nKeywords are symbolic identifiers that evaluate to themselves.\n\n```clojure\n:keyword ;; => \"keyword\"\n```\n\nSince in JS string constants fulfill the purpose of symbolic identifiers,\nkeywords compile to equivalent JS strings.\n\n```clojure\n(window.addEventListener :load handler false)\n```\n\nKeywords can also be invoked as functions, that desugars to associated\nvalue access in JS:\n\n```clojure\n(:bar foo) ;; => foo[\"bar\"]\n```\n\n\n#### Vectors\n\nWisp vectors are JS arrays.\n\n```clojure\n[ 1 2 3 4 ]\n```\nNote: Commas are whitespace & can be used if desired\n\n```clojure\n[ 1, 2, 3, 4]\n```\n\n\n#### Maps\n\nMaps are hash maps, plain JS objects. Note that unlike in clojure, keys cannot\nbe of arbitary types.\n\n```clojure\n{ \"foo\" bar :beep-bop \"bop\" 1 2 }\n```\n\nCommas are optional but can come handy for separating key value pairs.\n\n```clojure\n{ a 1, b 2 }\n```\n\n*In a future JSONs syntax may be made compatible with map syntax.*\n\n\n#### Lists\n\nYou can't have a lisp without lists! Wisp is homoiconic and its code is made\nup of lists representing expressions. The first item in the expression is a\nfunction, being invoked with rest items as arguments.\n\n\n```clojure\n(foo bar baz) ; => foo(bar, baz);\n```\n\n## Conventions\n\nWisp puts a lot of effort in making naming conventions transparent,\nby encouraging lisp conventions and then translating them to their\nequivalent JS conventions:\n\n```clojure\n(dash-delimited) ;; => dashDelimited\n(predicate?) ;; => isPredicate\n(**privates**) ;; => __privates__\n(list->vector) ;; => listToVector\n```\n\nAs a side effect some names can be expressed in a few ways, although\nit's considered to be an advantage.\n\n```clojure\n(parse-int x)\n(parseInt x)\n\n(array? x)\n(isArray x)\n```\n\n\n## Special forms\n\nThere are some functions in wisp that are special, in the sense that\nthey compile to JS expressions & cannot be passed around as regular\nfunctions. JS operators are represented in wisp as special forms\n\n\n#### Arithmetic operations\n\nWisp comes with special form for arithmetic operations.\n\n```clojure\n(+ a b) ; => a + b\n(+ a b c) ; => a + b + c\n(- a b) ; => a - b\n(* a b c) ; => a * b * c\n(/ a b) ; => a / b\n(mod a b) ; => a % 2\n```\n\n#### Comparison operations\n\nWisp comes with special forms for comparisons\n\n```clojure\n(identical? a b) ;; => a === b\n(identical? a b c) ;; => a === b && b === c\n(= a b) ;; => a == b\n(= a b c) ;; => a == b && b == c\n(> a b) ;; => a > b\n(>= a b) ;; => a >= b\n(< a b c) ;; => a < b && b < c\n(<= a b c) ;; => a <= b && b <= c\n```\n\n#### Logical operations\n\nWisp comes with special forms for logical operations\n\n```clojure\n(and a b) ;; => a && b\n(and a b c) ;; => a && b && c\n(or a b) ;; => a || b\n(and (or a b)\n (and c d)) ;; (a || b) && (c && d)\n```\n\n\n#### Definitions\n\nVariable definitions also happen through special forms.\n\n```clojure\n(def a) ; => var a = void(0);\n(def b 2) ; => var b = 2;\n```\n\n#### Assignments\n\nIn wisp new values can be set to a variables via `set!`\nspecial form. Note that in functional programing binding changes are\na bad practice, avoiding those would make your programs only better!\nStill if you need it you have it.\n\n```clojure\n(set! a 1)\n```\n\n#### Conditionals\n\nConditional code branching in wisp is expressed via\nif special form. First expression following `if` is a condition,\nif it evaluates to `true` result of the `if` expression is the\nsecond expression, otherwise it's the third expression.\n\n```clojure\n(if (< number 10)\n \"Digit\"\n \"Number\")\n```\n\nElse expression is optional, if missing and conditional evaluates to\n`true` result will be `nil`.\n\n```clojure\n(if (monday? today) \"How was your weekend\")\n```\n\n\n\n#### Combining expressions\n\nIn wisp is everything is an expression, but sometimes one might\nwant to combine multiple expressions into one, usually for the\npurpose of evaluating expressions that have side-effects\n\n```clojure\n(do\n (console.log \"Computing sum of a & b\")\n (+ a b))\n```\n\n`do` can take any number of expressions, even 0. If `0`, the result of\nevaluation will be nil.\n\n```clojure\n(do) ;; => nil\n```\n\n#### Bindings\n\nLet special form evaluates containing expressions in a\nlexical context of in which symbols in the bindings-forms (first item)\nare bound to their respective expression results.\n\n```clojure\n(let [a 1\n b (+ a c)]\n (+ a b))\n```\n\n\n#### Functions\n\nWisp functions are JS functions\n\n```clojure\n(fn [x] (+ x 1))\n```\n\nWisp functions can have names, just as in JS\n\n```clojure\n(fn increment [x] (+ x 1))\n```\n\nWisp functions can also contain documentation and some metadata.\nNote: Docstrings and metadata are not presented in compiled JS yet,\nbut in the future they will compile to comments associated with function.\n\n```clojure\n(fn incerement\n \"Returns a number one greater than given.\"\n {:added \"1.0\"}\n [x] (+ x 1))\n```\n\nWisp makes capturing of rest arguments a lot easier than JS. argument\nthat follows special `&` symbol will capture all the rest args in array.\n\n```clojure\n(fn [x & rest]\n (rest.reduce (fn [sum x] (+ sum x)) x))\n```\n\n#### Overloads\n\nIn wisp functions can be overloaded depending on number\nof arguments they take, without introspection of rest arguments.\n\n```clojure\n(fn sum\n \"Return the sum of all arguments\"\n {:version \"1.0\"}\n ([] 0)\n ([x] x)\n ([x y] (+ x y))\n ([x & more] (more.reduce (fn [x y] (+ x y)) x)))\n```\n\nIf function does not has variadic overload and more arguments is\npassed to it, it throws exception.\n\n```clojure\n(fn\n ([x] x)\n ([x y] (- x y)))\n```\n\n\n\n## Other Special Forms\n\n### Instantiation\n\nIn wisp type instantiation has a concise form. The type\nfunction just needs to be suffixed with `.` character\n\n```clojure\n(Type. options)\n```\n\nThe more verbose but more JS-like form is also valid\n\n```clojure\n(new Class options)\n```\n\n#### Method calls\n\nIn wisp method calls are no different from function calls, it's just that method\nfunctions are prefixed with `.` character\n\n```clojure\n(.log console \"hello wisp\")\n```\n\nMore JS-like forms are supported too!\n\n```clojure\n(window.addEventListener \"load\" handler false)\n```\n\n#### Attribute access\n\nIn wisp attribute access is also just like function\ncall. Attribute name just needs to be prefixed with `.-`\n\n```clojure\n(.-location window)\n```\n\nCompound properties can be access via `get` special form\n\n```clojure\n(get templates (.-id element))\n```\n\n#### Catching exceptions\n\nIn wisp exceptions can be handled via `try` special form. As with everything\nelse, the `try` form is also expression. It results to `nil` if no handling\ntakes place.\n\n```clojure\n(try (raise exception))\n```\n\nAlthough the `catch` form can be used to handle exceptions\n\n```clojure\n(try\n (raise exception)\n (catch error (.log console error)))\n```\n\nAlso `finally` clause can be used when necessary\n\n```clojure\n(try\n (raise exception)\n (catch error (recover error))\n (finally (.log console \"That was a close one!\")))\n```\n\n\n#### Throwing exceptions\n\nThrow special form allows throwing exceptions, although doing that is not\nidiomatic.\n\n```clojure\n(fn raise [message] (throw (Error. message)))\n```\n\n## Macros\n\nWisp has a programmatic macro system which allows the compiler to\nbe extended by user code. Many core constructs of Wisp are in fact\nnormal macros.\n\n#### quote\n\nBefore diving into macros too much, we need to learn about few more\nthings. In lisp any expression can be marked to prevent it from being\nevaluated. For instance, if you enter the symbol `foo` you will be\nevaluating the reference to the value of the corresponding variable.\n\n```clojure\nfoo\n```\n\nIf you wish to refer to the literal symbol, rather than reference you\ncould use\n\n```clojure\n(quote foo)\n```\n\nor more usually\n\n```clojure\n'foo\n```\n\nAny expression can be quoted, to prevent its evaluation. Although your\nresulting programs should not have these forms compiled to JS.\n\n```clojure\n'foo\n':bar\n'(a b)\n```\n\nWisp doesn’t have `unless` special form or a macro, but it's trivial\nto implement it via macro. Although let's try implemting it as a\nfunction to understand a use case for macro!\n\nWe want to execute body unless condition is `true`.\n\n```clojure\n(defn unless-fn [condition body]\n (if condition nil body))\n```\n\nAlthough following code will log \"should not print\" anyway, since\nfunction arguments are exectued before function is called.\n\n```clojure\n(unless-fn true (console.log \"should not print\"))\n```\n\nMacros solve this problem, because they do not evaluate their arguments\nimmediately. Instead, you get to choose when (and if!) the arguments\nto a macro are evaluated. Macros take items of the expression as\narguments and return new form that is compiled instead.\n\n```clojure\n(defmacro unless\n [condition form]\n (list 'if condition nil form))\n```\n\nThe body of unless macro executes at macro expansion time, producing an `if`\nform for compilation. Later this is compiled as usual. This way the compiled JS\nis a conditional instead of function call.\n\n```clojure\n(unless true (console.log \"should not print\"))\n```\n\n#### syntax-quote\n\nSimple macros like above could be written via templating, expressed\nas syntax-quoted forms.\n\n`syntax-quote` is almost the same as the plain `quote`, but it allows\nsub expressions to be unquoted so that form acts a template. Symbols\ninside form are resolved to help prevent inadvertent symbol capture.\nWhich can be done via `unquote` and `unquote-splicing` forms.\n\n```clojure\n(syntax-quote (foo (unquote bar)))\n(syntax-quote (foo (unquote bar) (unquote-splicing bazs)))\n```\n\nNote that there is special syntactic sugar for both unquoting operators:\n\nSyntax quote: Quote the form, but allow internal unquoting so that the form acts\nas template. Symbols inside form are resolved to help prevent inadvertent symbol\ncapture.\n\n```clojure\n`(foo bar)\n```\n\nUnquote: Use inside a syntax-quote to substitute an unquoted value.\n\n```clojure\n`(foo ~bar)\n```\n\nSplicing unquote: Use inside a syntax-quote to splice an unquoted\nlist into a template.\n\n```clojure\n`(foo ~bar ~@bazs)\n```\n\nFor example, the built-in `defn` macro can be defined expressed with simple\ntemplate macro. That's more or less how build-in `defn` macro is implemented.\n\n```clojure\n(defmacro define-fn\n [name & body]\n `(def ~name (fn ~@body)))\n```\n\nNow if we use `define-fn` form above defined macro will be expanded\nand compile time resulting into diff program output.\n\n```clojure\n(define-fn print\n [message]\n (.log console message))\n```\n\nNot all of the macros can be expressed via templating, but all of the\nlanguage is available at hand to assemble macro expanded form.\nFor instance let's define a macro to ease functional chaining popular\nin JS but usually expressed via method chaining. For example following\nAPI is pioneered by jQuery is very common in JS:\n\n```javascript\nopen(target, \"keypress\").\n filter(isEnterKey).\n map(getInputText).\n reduce(render)\n```\n\nUnfortunately though it usually requires all the functions need to be\nmethods of dsl object, which is very limited. Making third party\nfunctions second class. Via macros we can achieve similar chaining\nwithout such tradeoffs.\n\n```clojure\n(defmacro ->\n [& operations]\n (reduce-list\n (rest operations)\n (fn [form operation]\n (cons (first operation)\n (cons form (rest operation))))\n (first operations)))\n\n\n(->\n (open target :keypress)\n (filter enter-key?)\n (map get-input-text)\n (reduce render))\n```\n\n\n[homoiconicity]:http://en.wikipedia.org/wiki/Homoiconicity\n[clojure]:http://clojure.org/\n[macros]:http://clojure.org/macros\n[s-expressions]:http://en.wikipedia.org/wiki/S-expression\n[clojurescript]:https://github.com/clojure/clojurescript\n[markdown]:http://daringfireball.net/projects/markdown/\n\n", "readmeFilename": "Readme.md", "_id": "wisp@0.6.7", "dist": { "shasum": "46d13ffc9cc4ae2b9a36e6940e0a736af1de521b" }, "_from": "wisp@0.6.7", "_resolved": "https://registry.npmjs.org/wisp/-/wisp-0.6.7.tgz" }