4 ms·
Infix and unary operators are pretty straightforward, since they're just prefix versions of their JavaScript counterparts: (&& x y) => x && y (|| x y)
by evanrmurphy 16y ago
Infix and unary operators are pretty straightforward, since they're just prefix versions of their JavaScript counterparts:
(&& x y) => x && y
(|| x y) => x || y
(+ x y) => x + y
(- x y) => x - y
(* x y) => x * y
(/ x y) => x / y
(% x y) => x % y
(+= x y) => x += y
(-= x y) => x -= y
(*= x y) => x *= y
(/= x y) => x /= y
(%= x y) => x %= y
(= x y) => x = y
(== x y) => x == y
(=== x y) => x === y
(!= x y) => x != y
(!== x y) => x !== y
(! x) => !x
(++ x) => ++x
(-- x) => --x
(. x y) => x.y
While the dot operator's base form should be a prefixed s-expression like all the others, it may be awkward to use in practice:
(. (. ($ "body") (addClass "hidden")) (hide))
=> $("body").addClass("hidden").hide();
Since the dot operator is so common in idiomatic JavaScript, I propose allowing it to be infixed as a special case:
; expands to the above prefixed version
($ "body").(addClass "hidden").(hide)
For blocks we use a wrapper function rather than the curly brace block so that lexical scoping for variables can be ensured:
(do (= x 5) => (function() {
(++ x)) var x;
x = 5;
return ++x;
}).call(this);
The ternary operator:
(?: x y z) => (x ? y : z)
Perhaps we can create a useful distinction between the ternary operator and if-statements by giving if implicit do (just as cond has implicit progn in Common Lisp), but I'm not sure what the most elegant solution is. Thoughts?
Functions:
(function) => (function() {});
(function ()) => (function() {});
(function () => function() {
(+ 1 1)) return 1 + 1;
};
(= foo (function () => var foo;
(+ 1 1))) foo = function() {
return 1 + 1;
}
We could build a simple unhygienic macro system using the traditional quote ('), quasiquote (`), unquote (,) and unquote-splicing (,@) operators, as well as rest parameters (&). Here's how you might define a macro called unless:
; macro definition
(mac unless (x & args)
`(if (! ,x) ,@args))
; example usage
(unless true
(alert "Won't be executed"))
; expands to:
(if (! true)
(alert "Won't be executed"))
=> if (!true) {
alert("Won't be executed");
}
More coming...
- mrpixel 16y agoIMHO the ternary operator isn't of much use since there should be IF, returning values.
- evanrmurphy 16y agoArrays will be supported using one of these forms: '(1 2 3) => [1, 2, 3] ([] 1 2 3) [1 2 3] Objects with one of these: ({} a 1 b 2) => {a: 1, b: 2} {a 1 b 2} There's also the possibility of bringing ideas from David A. Wheeler's sweet-expressions (http://www.dwheeler.com/readable/ http://www.dwheeler.com/readable/). If curly braces are used for object literals, then the curly infix notation could not be borrowed, but there would still be an opportunity to borrow prefixed grouping symbols, e.g. f(x), and significant indentation: $("#something").click(function() alert("I was clicked!")) => $("#something").click(function() { alert("I was clicked!"); });
- sedachv 16y ago"While the dot operator's base form should be a prefixed s-expression like all the others, it may be awkward to use in practice" The solution isn't special syntax, it's macros. Check out Parenscript's chain: http://common-lisp.net/project/parenscript/reference.html#chain http://common-lisp.net/project/parenscript/reference.html#ch... "For blocks we use a wrapper function rather than the curly brace block so that lexical scoping for variables can be ensured." In most cases you can generate more efficient code by doing rudimentary control flow analysis. Look at how RETURN-FROM is implemented in the current Parenscript repository version. Also, speaking of lexical scoping don't forget that in JS loop variables only get a single binding. Scheme2JS uses a neat trick with with to implement the proper (per-iteration) binding (see this paper: http://www-sop.inria.fr/indes/scheme2js/files/icfp2006.pdf http://www-sop.inria.fr/indes/scheme2js/files/icfp2006.pdf). It's the only useful use of with I've ever encountered. "The ternary operator" Don't. The #1 goal of any new Lisp to JS translator should be to eliminate the statement/expression dichotomy. "We could build a simple unhygienic macro system using the traditional quote ('), quasiquote (`), unquote (,) and unquote-splicing (,@) operators, as well as rest parameters (&)." Take it one step further and make quasiquoting be able to build arrays at runtime. This is something that Daniel Gackle (gruseom) suggested for Parenscript and I need to implement. I actually want to take it a step further still and have a matching system like fare-matcher (http://www.cliki.net/fare-matcher http://www.cliki.net/fare-matcher) based around quasi-quoting. If you write all your code this way, you can go a long way towards eliminating dependence on the specific data structures you use for representing s-expressions. Right now I suspect you can go all the way, and that it's a viable strategy for making Parenscript self-hosting without adding runtime support for car/cdr to JavaScript. Speaking of runtime libraries, I think it's an implicit assumption you made already, but if you want to be like Coffeescript or Parenscript, you obviously need to avoid those.