Skip to content

Commit ed13012

Browse files
author
Sam Baxter
committed
First pass at propogating source locations
1 parent 638111d commit ed13012

File tree

1 file changed

+94
-57
lines changed

1 file changed

+94
-57
lines changed

src/cpsSyntax.ts

Lines changed: 94 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,26 @@ class CLet extends Node {
183183

184184
type CExpr = CLet | ITE | CApp;
185185

186+
const undefExpr: AExpr = t.identifier("undefined");
187+
188+
function addLoc(obj: any,
189+
start: number,
190+
end: number,
191+
loc: t.SourceLocation): any {
192+
for (const prop in Object.keys(obj)) {
193+
if (obj[prop] !== undefined &&
194+
(obj[prop].loc === undefined || obj[prop].loc === nullLoc)) {
195+
obj.start = start;
196+
obj.end = end;
197+
obj[prop] = loc;
198+
if (typeof obj[prop] === 'object') {
199+
addLoc(obj[prop], start, end, loc);
200+
}
201+
}
202+
}
203+
return obj;
204+
}
205+
186206
function cpsExprList(exprs: t.Expression[],
187207
k: (args: AExpr[]) => CExpr,
188208
ek: (arg: AExpr) => CExpr,
@@ -200,8 +220,6 @@ function cpsExprList(exprs: t.Expression[],
200220
}
201221
}
202222

203-
const undefExpr: AExpr = t.identifier("undefined");
204-
205223
function cpsObjMembers(mems: t.ObjectMember[],
206224
k: (args: AExpr[][]) => CExpr,
207225
ek: (arg: AExpr) => CExpr,
@@ -236,62 +254,64 @@ function cpsExpr(expr: t.Expression,
236254
case 'NullLiteral':
237255
case 'RegExpLiteral':
238256
case 'TemplateLiteral':
239-
return k(expr);
257+
return addLoc(k(expr), expr.start, expr.end, expr.loc);
240258
case 'ArrayExpression':
241-
return cpsExprList(<t.Expression[]>expr.elements, (args: AExpr[]) => {
259+
return addLoc(cpsExprList(<t.Expression[]>expr.elements, (args: AExpr[]) => {
242260
const arr = path.scope.generateUidIdentifier('arr');
243261
return new CLet('const', arr, new BArrayLit(args), k(arr));
244-
}, ek, path);
262+
}, ek, path), expr.start, expr.end, expr.loc);
245263
case "AssignmentExpression":
246-
return cpsExpr(expr.right, r => {
264+
return addLoc(cpsExpr(expr.right, r => {
247265
const assign = path.scope.generateUidIdentifier('assign');
248266
return new CLet('const', assign,
249267
new BAssign(expr.operator, expr.left, r), k(r));
250-
}, ek, path);
268+
}, ek, path), expr.start, expr.end, expr.loc);
251269
case 'BinaryExpression':
252-
return cpsExpr(expr.left, l =>
270+
return addLoc(cpsExpr(expr.left, l =>
253271
cpsExpr(expr.right, r => {
254272
let bop = path.scope.generateUidIdentifier('bop');
255273
return new CLet('const', bop, new BOp2(expr.operator, l, r), k(bop));
256-
}, ek, path), ek, path);
274+
}, ek, path), ek, path), expr.start, expr.end, expr.loc);
257275
case 'ConditionalExpression':
258-
return cpsExpr(expr.test, tst => new ITE(tst,
276+
return addLoc(cpsExpr(expr.test, tst => new ITE(tst,
259277
cpsExpr(expr.consequent, k, ek, path),
260-
cpsExpr(expr.alternate, k, ek, path)), ek, path);
278+
cpsExpr(expr.alternate, k, ek, path)), ek, path),
279+
expr.start, expr.end, expr.loc);
261280
case 'UnaryExpression':
262-
return cpsExpr(expr.argument, v => {
281+
return addLoc(cpsExpr(expr.argument, v => {
263282
let unop = path.scope.generateUidIdentifier('unop');
264283
return new CLet('const', unop, new BOp1(expr.operator, v), k(unop));
265-
}, ek, path);
284+
}, ek, path), expr.start, expr.end, expr.loc);
266285
case "FunctionExpression":
267286
let func = path.scope.generateUidIdentifier('func');
268-
return new CLet('const', func,
287+
return addLoc(new CLet('const', func,
269288
new BFun(expr.id, <t.Identifier[]>(expr.params),
270289
cpsStmt(expr.body,
271290
r => new CApp(<t.Identifier>(expr.params[0]), [r]),
272291
r => new CApp(<t.Identifier>(expr.params[1]), [r]),
273-
path)), k(func));
292+
path)), k(func)), expr.start, expr.end, expr.loc);
274293
case "CallExpression":
275-
return cpsExpr(expr.callee, f =>
294+
return addLoc(cpsExpr(expr.callee, f =>
276295
cpsExprList(<t.Expression[]>(expr.arguments), args => {
277296
const kFun = path.scope.generateUidIdentifier('kFun');
278297
const kErr = path.scope.generateUidIdentifier('kErr');
279298
const r = path.scope.generateUidIdentifier('r');
280299
return new CLet('const', kFun, new BFun(undefined, [r], k(r)),
281300
new CLet('const', kErr, new BFun(undefined, [r], ek(r)),
282301
new CApp(f, [kFun, kErr, ...args])));
283-
}, ek, path), ek, path);
302+
}, ek, path), ek, path), expr.start, expr.end, expr.loc);
284303
case 'MemberExpression':
285-
return cpsExpr(expr.object, o =>
304+
return addLoc(cpsExpr(expr.object, o =>
286305
cpsExpr(expr.property, p => {
287306
const obj = path.scope.generateUidIdentifier('obj');
288307
return new CLet('const', obj, new BGet(o, p), k(obj));
289-
}, ek, path), ek, path);
308+
}, ek, path), ek, path), expr.start, expr.end, expr.loc);
290309
case 'NewExpression':
291310
const tmp = path.scope.generateUidIdentifier('new');
292-
return new CLet('const', tmp, expr, k(tmp));
311+
return addLoc(new CLet('const', tmp, expr, k(tmp)),
312+
expr.start, expr.end, expr.loc);
293313
case 'ObjectExpression':
294-
return cpsObjMembers(<t.ObjectMember[]>expr.properties,
314+
return addLoc(cpsObjMembers(<t.ObjectMember[]>expr.properties,
295315
(mems: AExpr[][]) => {
296316
const obj = path.scope.generateUidIdentifier('obj');
297317
const fields = new Map();
@@ -302,13 +322,13 @@ function cpsExpr(expr: t.Expression,
302322
return new CLet('const', obj, new BObj(fields), k(obj));
303323
},
304324
ek,
305-
path);
325+
path), expr.start, expr.end, expr.loc);
306326
case 'UpdateExpression':
307-
return cpsExpr(expr.argument, (v: AExpr) => {
327+
return addLoc(cpsExpr(expr.argument, (v: AExpr) => {
308328
const tmp = path.scope.generateUidIdentifier('update');
309329
return new CLet('const', tmp,
310330
new BIncrDecr(expr.operator, v, expr.prefix), k(tmp));
311-
}, ek, path);
331+
}, ek, path), expr.start, expr.end, expr.loc);
312332
}
313333
throw new Error(`${expr.type} not yet implemented`);
314334
}
@@ -321,58 +341,64 @@ function cpsStmt(stmt: t.Statement,
321341
case "BlockStatement": {
322342
let [head, ...tail] = stmt.body;
323343
if (head === undefined) {
324-
return k(undefExpr);
344+
return addLoc(k(undefExpr), stmt.start, stmt.end, stmt.loc);
325345
} else if (tail === []) {
326-
return cpsStmt(head, k, ek, path);
346+
return addLoc(cpsStmt(head, k, ek, path), stmt.start, stmt.end, stmt.loc);
327347
} else {
328-
return cpsStmt(head, v => cpsStmt(t.blockStatement(tail),
329-
k, ek, path), ek, path);
348+
return addLoc(cpsStmt(head, v => cpsStmt(t.blockStatement(tail),
349+
k, ek, path), ek, path), stmt.start, stmt.end, stmt.loc);
330350
}
331351
}
332352
case "BreakStatement":
333-
return cpsExpr(stmt.label, label => new CApp(label, [undefExpr]), ek, path);
353+
return addLoc(cpsExpr(stmt.label, label =>
354+
new CApp(label, [undefExpr]), ek, path), stmt.start, stmt.end, stmt.loc);
334355
case "EmptyStatement":
335-
return k(undefExpr);
356+
return addLoc(k(undefExpr), stmt.start, stmt.end, stmt.loc);
336357
case "ExpressionStatement":
337-
return cpsExpr(stmt.expression, _ => k(undefExpr), ek, path);
358+
return addLoc(cpsExpr(stmt.expression, _ =>
359+
k(undefExpr), ek, path), stmt.start, stmt.end, stmt.loc);
338360
case "IfStatement":
339-
return cpsExpr(stmt.test, tst => new ITE(tst,
361+
return addLoc(cpsExpr(stmt.test, tst => new ITE(tst,
340362
cpsStmt(stmt.consequent, k, ek, path),
341-
cpsStmt(stmt.alternate, k, ek, path)), ek, path);
363+
cpsStmt(stmt.alternate, k, ek, path)), ek, path),
364+
stmt.start, stmt.end, stmt.loc);
342365
case "LabeledStatement": {
343366
const kErr = path.scope.generateUidIdentifier('kErr');
344-
return cpsExpr(t.callExpression(t.functionExpression(undefined,
367+
return addLoc(cpsExpr(t.callExpression(t.functionExpression(undefined,
345368
[stmt.label, kErr], flatBodyStatement([stmt.body])), []),
346-
k, ek, path);
369+
k, ek, path), stmt.start, stmt.end, stmt.loc);
347370
}
348371
case "ReturnStatement":
349372
let returnK = (r: AExpr) =>
350373
new CApp(<t.Identifier>(<ReturnStatement>stmt).kArg, [r]);
351-
return cpsExpr(stmt.argument, r => returnK(r), ek, path);
374+
return addLoc(cpsExpr(stmt.argument, r =>
375+
returnK(r), ek, path), stmt.start, stmt.end, stmt.loc);
352376
case 'ThrowStatement':
353-
return cpsExpr(stmt.argument, ek, v => new CApp(v, [undefExpr]), path);
377+
return addLoc(cpsExpr(stmt.argument, ek, v =>
378+
new CApp(v, [undefExpr]), path), stmt.start, stmt.end, stmt.loc);
354379
case 'TryStatement':
355380
const kFun = path.scope.generateUidIdentifier('kFun');
356381
const kErr = path.scope.generateUidIdentifier('kErr');
357-
return cpsExpr(t.callExpression(t.functionExpression(undefined,
382+
return addLoc(cpsExpr(t.callExpression(t.functionExpression(undefined,
358383
[kFun, kErr],
359384
stmt.block), []), k, e =>
360385
new CLet('const', stmt.handler.param, new BAtom(e),
361-
cpsStmt(stmt.handler.body, k, ek, path)), path);
386+
cpsStmt(stmt.handler.body, k, ek, path)), path),
387+
stmt.start, stmt.end, stmt.loc);
362388
case "VariableDeclaration": {
363389
const { declarations } = stmt;
364390
const [head, ...tail] = declarations;
365391
if (head === undefined) {
366-
return k(undefExpr);
392+
return addLoc(k(undefExpr), stmt.start, stmt.end, stmt.loc);
367393
} else if (tail === []) {
368-
return cpsExpr(head.init, v =>
394+
return addLoc(cpsExpr(head.init, v =>
369395
new CLet(stmt.kind, <t.Identifier>head.id, new BAtom(v), k(undefExpr)),
370-
ek, path);
396+
ek, path), stmt.start, stmt.end, stmt.loc);
371397
} else {
372-
return cpsExpr(head.init, v =>
398+
return addLoc(cpsExpr(head.init, v =>
373399
new CLet(stmt.kind, <t.Identifier>head.id, new BAtom(v),
374400
cpsStmt(t.variableDeclaration(stmt.kind, tail), k, ek, path)),
375-
ek, path);
401+
ek, path), stmt.start, stmt.end, stmt.loc);
376402
}
377403
}
378404
default:
@@ -383,30 +409,38 @@ function cpsStmt(stmt: t.Statement,
383409
function generateBExpr(bexpr: BExpr): t.Expression {
384410
switch (bexpr.type) {
385411
case 'BFun':
386-
return t.functionExpression(bexpr.id,
412+
return addLoc(t.functionExpression(bexpr.id,
387413
bexpr.args,
388-
flatBodyStatement(generateJS(bexpr.body)));
414+
flatBodyStatement(generateJS(bexpr.body))),
415+
bexpr.start, bexpr.end, bexpr.loc);
389416
case 'atom':
390417
return bexpr.atom;
391418
case 'op2':
392-
return t.binaryExpression(bexpr.name, bexpr.l, bexpr.r);
419+
return addLoc(t.binaryExpression(bexpr.name, bexpr.l, bexpr.r),
420+
bexpr.start, bexpr.end, bexpr.loc);
393421
case 'op1':
394-
return t.unaryExpression(bexpr.name, bexpr.v);
422+
return addLoc(t.unaryExpression(bexpr.name, bexpr.v),
423+
bexpr.start, bexpr.end, bexpr.loc);
395424
case 'assign':
396-
return t.assignmentExpression(bexpr.operator, bexpr.x, bexpr.v);
425+
return addLoc(t.assignmentExpression(bexpr.operator, bexpr.x, bexpr.v),
426+
bexpr.start, bexpr.end, bexpr.loc);
397427
case 'obj':
398428
const properties : t.ObjectProperty[] = [];
399429
bexpr.fields.forEach((value, key) =>
400430
properties.push(t.objectProperty(key, value)));
401-
return t.objectExpression(properties);
431+
return addLoc(t.objectExpression(properties),
432+
bexpr.start, bexpr.end, bexpr.loc);
402433
case 'get':
403-
return t.memberExpression(bexpr.object, bexpr.property);
434+
return addLoc(t.memberExpression(bexpr.object, bexpr.property),
435+
bexpr.start, bexpr.end, bexpr.loc);
404436
case 'NewExpression':
405437
return bexpr;
406438
case 'incr/decr':
407-
return t.updateExpression(bexpr.operator, bexpr.argument, bexpr.prefix);
439+
return addLoc(t.updateExpression(bexpr.operator, bexpr.argument, bexpr.prefix),
440+
bexpr.start, bexpr.end, bexpr.loc);
408441
case 'arraylit':
409-
return t.arrayExpression(bexpr.arrayItems);
442+
return addLoc(t.arrayExpression(bexpr.arrayItems),
443+
bexpr.start, bexpr.end, bexpr.loc);
410444
case 'update':
411445
throw new Error(`${bexpr.type} generation is not yet implemented`);
412446
}
@@ -415,14 +449,17 @@ function generateBExpr(bexpr: BExpr): t.Expression {
415449
function generateJS(cexpr: CExpr): t.Statement[] {
416450
switch (cexpr.type) {
417451
case 'app':
418-
return [t.returnStatement(t.callExpression(cexpr.f, cexpr.args))];
452+
return [addLoc(t.returnStatement(t.callExpression(cexpr.f, cexpr.args)),
453+
cexpr.start, cexpr.end, cexpr.loc)];
419454
case 'ITE':
420-
return [t.ifStatement(cexpr.e1,
455+
return [addLoc(t.ifStatement(cexpr.e1,
421456
flatBodyStatement(generateJS(cexpr.e2)),
422-
flatBodyStatement(generateJS(cexpr.e3)))];
457+
flatBodyStatement(generateJS(cexpr.e3))),
458+
cexpr.start, cexpr.end, cexpr.loc)];
423459
case 'let':
424460
const decl = letExpression(cexpr.x, generateBExpr(cexpr.named), cexpr.kind);
425-
return [decl, ...generateJS(cexpr.body)];
461+
return [addLoc(decl, cexpr.start, cexpr.end, cexpr.loc),
462+
...generateJS(cexpr.body)];
426463
}
427464
}
428465

0 commit comments

Comments
 (0)