This repository has been archived by the owner on Oct 15, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
swap-macro.js
executable file
·101 lines (87 loc) · 2.57 KB
/
swap-macro.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/usr/bin/env node
var recast = require('recast');
var util = require('../lib');
var types = util.types;
var n = types.namedTypes;
var b = types.builders;
var assert = require('assert');
/**
* Treats calls to `swap` as a macro to swap the identifiers passed to swap.
*
* swap(left, right);
*
* Becomes
*
* var tmp;
* tmp = left;
* left = right;
* right = tmp;
*
* @param {ast-types.Node} ast
* @return {ast-types.Node} Returns `ast`.
*/
function transform(ast) {
var replaced = [];
types.traverse(ast, function(node) {
if (n.ExpressionStatement.check(node)) {
if (isSwapCall(this.get('expression'))) {
// swap(left, right)
var expression = node.expression;
assert.equal(expression.arguments.length, 2, 'expected 2 arguments to `swap`, got ' + expression.arguments.length);
var left = expression.arguments[0];
var right = expression.arguments[1];
assert.ok(
n.Identifier.check(left) || n.MemberExpression.check(left),
'expected first argument of `swap` to be an Identifier or MemberExpression, found ' + left.type
);
assert.ok(
n.Identifier.check(right) || n.MemberExpression.check(right),
'expected second argument of `swap` to be an Identifier or MemberExpression, found ' + right.type
);
var tmp = util.uniqueIdentifier(this.scope);
replaced.push(expression);
this.replace(
// var tmp = left;
b.variableDeclaration(
'var',
[b.variableDeclarator(tmp, left)]
),
// left = right
b.expressionStatement(b.assignmentExpression(
'=',
left,
right
)),
// right = tmp
b.expressionStatement(b.assignmentExpression(
'=',
right,
tmp
))
);
}
} else if (isSwapCall(this) && replaced.indexOf(node) < 0) {
throw new Error('unexpected `swap` macro used as an expression instead of a statement');
}
});
return ast;
}
function isSwapCall(path) {
return n.CallExpression.check(path.value) && util.isReference(path.get('callee'), 'swap');
}
function readStdin(callback) {
var stdin = '';
process.stdin.setEncoding('utf8');
process.stdin.on('readable', function() {
var chunk = process.stdin.read();
if (chunk !== null) {
stdin += chunk;
}
});
process.stdin.on('end', function() {
callback(stdin);
});
}
readStdin(function(stdin) {
process.stdout.write(recast.print(transform(recast.parse(stdin))).code);
});