Skip to content

Commit b425713

Browse files
committed
lots of work for tracing and visualizing the traces
SQUASHED: AUTO-COMMIT-demos-tom-astWrapper.js,AUTO-COMMIT-demos-tom-babel-plugin-tracer.js,AUTO-COMMIT-demos-tom-defect-demo-plugin.js,AUTO-COMMIT-demos-tom-defect-demo-plugin.md,AUTO-COMMIT-demos-tom-playground.js,AUTO-COMMIT-demos-tom-plugin-explorer-worker.js,AUTO-COMMIT-demos-tom-trace.js,AUTO-COMMIT-demos-tom-trace-visualization.html,AUTO-COMMIT-demos-tom-trace-visualization.js,AUTO-COMMIT-demos-tom-wrapAST.js,AUTO-COMMIT-src-components-tools-lively-plugin-explorer.js,AUTO-COMMIT-src-components-tools-lively-plugin-explorer-playground.workspace,AUTO-COMMIT-src-components-tools-plugin-selector.js,AUTO-COMMIT-src-components-tools-plugin-selector-list.json,AUTO-COMMIT-src-components-tools-plugin-selector-list.md,AUTO-COMMIT-src-components-tools-trace-visualization.html,AUTO-COMMIT-src-components-tools-trace-visualization.js,
1 parent 8ba8c37 commit b425713

File tree

10 files changed

+881
-136
lines changed

10 files changed

+881
-136
lines changed

demos/tom/babel-plugin-tracer.js

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,53 @@
11
import Trace from 'demos/tom/trace.js';
2+
import wrapAST from 'demos/tom/wrapAST.js';
23

34
export default function({ types: t }) {
45
function error(path, message) {
56
throw path.buildCodeFrameError(message);
67
}
78

89
const returnVisitor = {
9-
ReturnStatement(path) {
10+
ReturnStatement(path, state) {
1011
if (path.node.alreadyVisited) {
1112
return;
1213
}
1314
path.node.alreadyVisited = true;
14-
const log = callOnTrace('return');
15+
1516
const returnValue = path.node.argument ? path.node.argument : t.identifier('undefined');
16-
path.node.argument = t.sequenceExpression([log, returnValue])
17+
const returnNode = callOnTrace('return', [location(path.node, state), returnValue]);
18+
path.node.argument = returnNode;
1719
}
1820
}
1921

2022
function callOnTrace(methodName, args = []) {
2123
return t.callExpression(t.memberExpression(t.identifier(Trace.traceIdenifierName), t.identifier(methodName)),
2224
args);
2325
}
26+
27+
function location(astNode, state) {
28+
const filename = state.file.opts.filename;
29+
30+
const start = astNode.loc.start;
31+
const end = astNode.loc.end;
32+
33+
const locationObject = {
34+
filename,
35+
startLine: start.line,
36+
startColumn: start.column,
37+
endLine: end.line,
38+
endColumn: end.column
39+
}
40+
41+
const id = Trace.register(locationObject);
42+
43+
return t.numericLiteral(id);
44+
}
2445

25-
function modifyFunction(name, path) {
46+
function modifyFunction(name, path, state) {
2647
const body = path.get('body');
27-
body.unshiftContainer('body', t.expressionStatement(callOnTrace('enterFunction', [t.stringLiteral(name)])));
28-
body.pushContainer('body', t.expressionStatement(callOnTrace('leave')));
29-
path.traverse(returnVisitor);
48+
body.unshiftContainer('body', t.expressionStatement(callOnTrace( 'enterFunction', [location(path.node, state), t.stringLiteral(name)])));
49+
body.pushContainer('body', t.expressionStatement(callOnTrace('leave', [location(path.node, state)])));
50+
path.traverse(returnVisitor, state);
3051
}
3152

3253
function resolveName(callee) {
@@ -42,7 +63,6 @@ export default function({ types: t }) {
4263
function nameFromCallExpression(path) {
4364
const callee = path.node.callee;
4465
if (callee.type === 'MemberExpression') {
45-
4666
return resolveName(callee)
4767
} else {
4868
return callee.name || 'anonymous function';
@@ -52,28 +72,73 @@ export default function({ types: t }) {
5272
return {
5373
name: 'tracer',
5474
visitor: {
75+
Program(path) {
76+
// wrapAST(path.node, {notify(){console.log(...arguments)}})
77+
},
5578
CallExpression(path) {
5679
if (path.node.alreadyVisited || path.isGenerated()) {
5780
return;
5881
}
59-
debugger
6082
const name = nameFromCallExpression(path);
6183
path.node.alreadyVisited = true;
62-
const log = callOnTrace('aboutToEnter', [t.stringLiteral(name)]);
63-
const sequence = t.sequenceExpression([log, path.node]);
64-
path.replaceWith(t.expressionStatement(sequence));
84+
const log = callOnTrace('aboutToEnter', [location(path.node, this), t.stringLiteral(name)]);
85+
path.insertBefore(log)
6586
},
6687
ArrowFunctionExpression(path) {
6788

6889
},
6990
"ClassMethod|ObjectMethod"(path) {
7091
const name = path.node.key.name;
71-
modifyFunction(name, path);
92+
modifyFunction(name, path, this);
7293
},
7394
"FunctionDeclaration|FunctionExpression"(path) {
7495
const id = path.node.id;
7596
const name = id ? id.name : 'anonymous function';
76-
modifyFunction(name, path);
97+
modifyFunction(name, path, this);
98+
},
99+
Loop(path) {
100+
path.insertBefore(callOnTrace('beginLoop', [location(path.node, this), t.stringLiteral(path.type)]))
101+
path.insertAfter(callOnTrace('endLoop', [location(path.node, this)]))
102+
},
103+
ForStatement(path) {
104+
path.get('body').unshiftContainer('body', callOnTrace('nextLoopIteration', [location(path.node, this), ...path.node.init.declarations.map(declaration => declaration.id)]));
105+
},
106+
ForOfStatement(path) {
107+
108+
},
109+
ForInStatement(path) {
110+
111+
},
112+
Conditional(path) {
113+
if(path.node.alreadyVisited) {
114+
return;
115+
}
116+
117+
path.node.alreadyVisited = true;
118+
119+
path.node.test = callOnTrace('conditionTest', [
120+
location(path.node.test, this),
121+
path.node.test
122+
]);
123+
124+
// do not log else ifs
125+
if(path.parent.type !== 'IfStatement') {
126+
path.insertBefore(callOnTrace('beginCondition', [
127+
location(path.node, this),
128+
t.stringLiteral(path.type)
129+
]));
130+
path.insertAfter(callOnTrace('endCondition', [location(path.node, this)]));
131+
}
132+
},
133+
134+
AssignmentExpression(path) {
135+
if(path.isGenerated()) {
136+
return;
137+
}
138+
path.node.right = callOnTrace('assignment', [
139+
location(path.node, this),
140+
t.stringLiteral(resolveName(path.node.left)), path.node.right
141+
]);
77142
}
78143
}
79144
}

demos/tom/defect-demo-plugin.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export default function({ types: t }) {
2+
return {
3+
name: 'demo-plugin',
4+
visitor: {
5+
Conditional(path) {
6+
path.get('test').insertBefore(t.stringLiteral('start'));
7+
path.get('test').insertAfter(t.stringLiteral('after'));
8+
},
9+
AssignmentExpression(path) {
10+
alert(path.node.left.name)
11+
}
12+
}
13+
}
14+
}

demos/tom/playground.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1-
export default function foo(a, b) {
2-
deb(); return a + b;
1+
export default function({types: t}) {
2+
3+
return {
4+
name: 'test',
5+
visitor: {
6+
CallExpression(path) {
7+
if (path.node.modified) {
8+
return;
9+
}
10+
path.node.modified = true;
11+
12+
path.node.callee.name = 'test_' + path.node.callee.name;
13+
}
14+
}
15+
}
316
}

demos/tom/plugin-explorer-worker.js

Lines changed: 105 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,111 @@ importScripts(lively4url + '/demos/tom/plugin-explorer-systemjs-config.js')
1212
// not sure why I need this but without it I cannot import the plugins
1313
System.import(pluginTransformationPlugin);
1414

15+
const enumerationPlugin = function() {
1516

16-
Promise.all(['demos/tom/trace.js', 'systemjs-babel-build'].map(name => System.import(name)))
17-
.then(function(arr) {
18-
const Trace = arr[0].default;
19-
const babel = arr[1].default.babel;
20-
21-
self.onmessage = function(msg) {
22-
const config = {
23-
filename: 'tmpfile.js',
24-
moduleIds: false,
25-
babelrc: false,
26-
};
27-
System.config({
28-
meta: {
29-
'*.js': pluginOptions,
30-
[pluginTransformationPlugin]: moduleOptionsNon
31-
}
32-
})
17+
let counter = 0;
3318

34-
Promise.all(msg.data.urls.map(url => System.import(url)))
35-
.then(function(modules) {
36-
config.plugins = modules.map(module => module.default);
37-
config.sourceFileName = 'tmpfile.js';
38-
window[Trace.traceIdenifierName] = new Trace();
39-
const result = babel.transform(msg.data.source, config);
40-
debugger
41-
postMessage({transformedAST: JSON.stringify(result.ast), transformedCode: result.code, trace: window[Trace.traceIdenifierName]});
42-
})
19+
const visitor = {
20+
enter(path) {
21+
path.node.traceid = counter++;
4322
}
44-
});
23+
};
24+
25+
return {
26+
visitor: {
27+
Program(path) {
28+
path.node.traceid = counter++;
29+
path.traverse(visitor)
30+
}
31+
}
32+
}
33+
}
34+
35+
const enumerationConfig = {
36+
plugins: [enumerationPlugin]
37+
}
38+
39+
async function importPlugin(url) {
40+
const module = await System.import(url);
41+
const plugin = module.default;
42+
43+
const modifiedPlugin = function(...args) {
44+
const result = plugin(...args)
45+
result.name = result.name || 'Please name your plugin!';
46+
return result;
47+
}
48+
49+
return modifiedPlugin;
50+
}
51+
52+
function importPlugins(urls) {
53+
return Promise.all(urls.map(url => importPlugin(url)))
54+
.then(plugins => {
55+
let counter = 0;
56+
for (const plugin of plugins) {
57+
if (plugin.name === 'Please name your plugin!') {
58+
plugin.name += counter;
59+
counter++;
60+
}
61+
}
62+
return plugins;
63+
})
64+
}
65+
66+
const importPromise = Promise.all(['demos/tom/trace.js', 'systemjs-babel-build', 'demos/tom/wrapAST.js'].map(name =>
67+
System.import(name)));
68+
69+
self.onmessage = function(msg) {
70+
importPromise.then(function(imports) {
71+
const Trace = imports[0].default;
72+
const babel = imports[1].default.babel;
73+
const wrapAST = imports[2].default;
74+
75+
const config = {
76+
filename: 'tmpfile.js',
77+
moduleIds: false,
78+
babelrc: false,
79+
};
80+
System.config({
81+
meta: {
82+
'*.js': pluginOptions,
83+
[pluginTransformationPlugin]: moduleOptionsNon
84+
}
85+
});
86+
87+
const trace = new Trace();
88+
// make it globally available for use in plugins
89+
window[Trace.traceIdenifierName] = trace;
90+
91+
importPlugins(msg.data.urls)
92+
.then(function(modules) {
93+
config.plugins = modules;
94+
config.sourceFileName = 'tmpfile.js';
95+
config.sourceMaps = true;
96+
97+
config.wrapPluginVisitorMethod = (pluginAlias, visitorType, callback) => {
98+
return (...args) => {
99+
trace.enterPlugin(pluginAlias);
100+
callback(...args);
101+
trace.leavePlugin(pluginAlias);
102+
}
103+
};
104+
105+
trace.startTraversion();
106+
const ast = babel.transform(msg.data.source, enumerationConfig).ast;
107+
const oldASTAsString = JSON.stringify(ast);
108+
109+
wrapAST(ast, trace);
110+
const result = babel.transformFromAst(ast, undefined, config);
111+
112+
// const result = babel.transform(msg.data.source, config);
113+
postMessage({
114+
oldAST: oldASTAsString,
115+
transformedAST: JSON.stringify(result.ast),
116+
transformedCode: result.code,
117+
trace: JSON.stringify(trace),
118+
locations: Trace.locations
119+
});
120+
})
121+
})
122+
}

0 commit comments

Comments
 (0)