Skip to content

Instantly share code, notes, and snippets.

@trxcllnt
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trxcllnt/96d81d6afbbaa25cd841 to your computer and use it in GitHub Desktop.
Save trxcllnt/96d81d6afbbaa25cd841 to your computer and use it in GitHub Desktop.
Macros to rewrite tail-recursive immediately invoked function expressions (IIFE) and function declarations as tight while loops.
/* output *//*
var result;
var acc = 1, x = 10;
while (true) {
if (x <= 1) {
// non-recursive return invocations aren't rewritten
acc = log(acc);
break;
} else {
acc = acc * x;
x = x - 1;
continue;
}
}
result = acc;
console.log(result);
function calc_fact(start) {
var acc$2 = 1, x$2 = start;
while (true) {
if (x$2 <= 1) {
// non-recursive return invocations aren't rewritten
acc$2 = log(acc$2);
break;
} else {
acc$2 = acc$2 * x$2;
x$2 = x$2 - 1;
continue;
}
}
return acc$2;
}
function fact(acc$2, x$2) {
var acc$2 = acc$2, x$2 = x$2;
while (true) {
if (x$2 <= 1) {
// non-recursive return invocations aren't rewritten
acc$2 = log(acc$2);
break;
} else {
acc$2 = acc$2 * x$2;
x$2 = x$2 - 1;
continue;
}
}
return acc$2;
}
console.log(fact(1, 10));
function log(value) {
return console.log(value) && value || value;
}
*/
macro tailrec {
rule { function $name:ident ($arg:ident (,) ...) { $body ... } } => {
function $name ($arg (,) ...) {
return tailrec $name ($arg(,) ...) {
$body ...
}($arg (,) ...)
}
}
case infix { return | _ $name ($arg:ident (,) ...) { $body ... }($exp:expr (,) ...) } => {
letstx $arg0 = #{ $arg ... }.slice(0, 1);
return #{
tailrec $name ($arg(,) ...) {
$body ...
}($exp (,) ...)
return $arg0
}
}
case infix { $ret:ident = | _ $name ($arg:ident (,) ...) { $body ... }($exp:expr (,) ...) } => {
letstx $arg0 = #{ $arg ... }.slice(0, 1);
return #{
var $ret;
tailrec $name ($arg(,) ...) {
$body ...
}($exp (,) ...)
$ret = $arg0
}
}
case infix { $ret:expr = | _ $name ($arg:ident (,) ...) { $body ... }($exp:expr (,) ...) } => {
letstx $arg0 = #{ $arg ... }.slice(0, 1);
return #{
tailrec $name ($arg(,) ...) {
$body ...
}($exp (,) ...)
$ret = $arg0
}
}
case {_ $name ($arg:ident (,) ...) { $body ... }($exp:expr (,) ...) } => {
var arg0 = #{ $arg ... }[0],
bstx = #{ $body ... }[0];
letstx $inner ... = localExpand(withSyntax(
$arg0 = [makeIdent(unwrapSyntax(arg0), arg0)],
$return = [makeKeyword("return", bstx)],
) #{
let $return = macro {
case {_ $name ($val:expr (,) $[...]) } => {
letstx $args $[...] = #{ $arg ... };
letstx $vals $[...] = #{ $val $[...] };
return #{
$($args = $vals) (;) $[...] ;
continue
};
}
rule { $val:expr } => {
$arg0 = $val;
break
}
rule { } => {
$arg0 = undefined;
break
}
}
var $($arg = $exp) (,) ... ;
while(true) {
$body ...
}
});
return #{
$inner ...
let $return = macro { rule { } => { return } }
};
}
}
result = tailrec fact(acc, x) {
if (x <= 1) {
// non-recursive return invocations aren't rewritten
return log(acc);
} else {
return fact(acc * x, x - 1);
}
}(1, 10);
console.log(result);
function calc_fact(start) {
return tailrec fact(acc, x) {
if (x <= 1) {
// non-recursive return invocations aren't rewritten
return log(acc);
} else {
return fact(acc * x, x - 1);
}
}(1, start);
}
tailrec function fact(acc, x) {
if (x <= 1) {
// non-recursive return invocations aren't rewritten
return log(acc);
} else {
return fact(acc * x, x - 1);
}
}
console.log(fact(1, 10));
function log(value) {
return console.log(value) && value || value;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment