Skip to content

Commit 2de49e2

Browse files
authored
feat: add parent pointers to nodes and a traverse function (#251)
Also throw in some other breaking changes and other cleanups. BREAKING CHANGE: All nodes now have a `parentNode` field. Shorthand object initializers now have a `null` value rather than using the same node as the key and the value. This ensures no node gets traversed twice in a traversal. The `range` field has been removed from nodes. Code should now use `start` and `end` instead.
1 parent 17651ec commit 2de49e2

File tree

275 files changed

+3652
-7447
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

275 files changed

+3652
-7447
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "decaffeinate-parser",
33
"description": "A better AST for CoffeeScript, inspired by CoffeeScriptRedux.",
4+
"version": "0.0.0-development",
45
"main": "dist/parser.js",
56
"module": "dist/parser.mjs",
67
"types": "dist/parser.d.ts",

src/mappers/mapObj.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default function mapObj(context: ParseContext, node: Obj): ObjectInitiali
2121
members.push(new ObjectInitialiserMember(
2222
line, column, start, end, raw,
2323
value,
24-
value
24+
null
2525
));
2626
} else if (property instanceof Assign && property.context === 'object') {
2727
let key = mapAny(context, property.variable);

src/nodes.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import ParseContext from './util/ParseContext';
44
export type ChildField = Node | Array<Node | null> | null;
55

66
export abstract class Node {
7-
readonly range: [number, number];
7+
parentNode: Node | null = null;
88

99
constructor(
1010
readonly type: string,
@@ -14,8 +14,6 @@ export abstract class Node {
1414
readonly end: number,
1515
readonly raw: string,
1616
) {
17-
this.range = [start, end];
18-
this.raw = raw;
1917
}
2018

2119
getChildren(): Array<Node> {
@@ -316,7 +314,8 @@ export class ObjectInitialiserMember extends Node {
316314
end: number,
317315
raw: string,
318316
readonly key: Node,
319-
readonly expression: Node,
317+
// If null, this is a shorthand initializer and the key and value are the same.
318+
readonly expression: Node | null,
320319
) {
321320
super('ObjectInitialiserMember', line, column, start, end, raw);
322321
}

src/parser.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,32 @@ import lex from 'coffee-lex';
22
import * as CoffeeScript from 'decaffeinate-coffeescript';
33
import { patchCoffeeScript } from './ext/coffee-script';
44
import mapProgram from './mappers/mapProgram';
5-
import { Program } from './nodes';
5+
import { Node, Program } from './nodes';
66
import fixLocations from './util/fixLocations';
77
import ParseContext from './util/ParseContext';
88

99
export function parse(source: string): Program {
1010
patchCoffeeScript();
1111
let context = ParseContext.fromSource(source, lex, CoffeeScript.nodes);
1212
fixLocations(context, context.ast);
13-
return mapProgram(context);
13+
let program = mapProgram(context);
14+
traverse(program, (node, parent) => {
15+
node.parentNode = parent;
16+
});
17+
return program;
18+
}
19+
20+
export function traverse(
21+
node: Node,
22+
callback: (node: Node, parent: Node | null) => boolean | void
23+
): void {
24+
function traverseRec(currentNode: Node, currentParent: Node | null): void {
25+
let shouldDescend = callback(currentNode, currentParent);
26+
if (shouldDescend !== false) {
27+
for (let child of currentNode.getChildren()) {
28+
traverseRec(child, currentNode);
29+
}
30+
}
31+
}
32+
traverseRec(node, null);
1433
}

test/examples/addition/output.json

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,45 @@
11
{
22
"body": {
33
"column": 1,
4+
"end": 5,
45
"inline": false,
56
"line": 1,
6-
"range": [
7-
0,
8-
5
9-
],
107
"raw": "3 + 4",
8+
"start": 0,
119
"statements": [
1210
{
1311
"column": 1,
12+
"end": 5,
1413
"left": {
1514
"column": 1,
1615
"data": 3,
16+
"end": 1,
1717
"line": 1,
18-
"range": [
19-
0,
20-
1
21-
],
2218
"raw": "3",
19+
"start": 0,
2320
"type": "Int"
2421
},
2522
"line": 1,
26-
"range": [
27-
0,
28-
5
29-
],
3023
"raw": "3 + 4",
3124
"right": {
3225
"column": 5,
3326
"data": 4,
27+
"end": 5,
3428
"line": 1,
35-
"range": [
36-
4,
37-
5
38-
],
3929
"raw": "4",
30+
"start": 4,
4031
"type": "Int"
4132
},
33+
"start": 0,
4234
"type": "PlusOp"
4335
}
4436
],
4537
"type": "Block"
4638
},
4739
"column": 1,
40+
"end": 5,
4841
"line": 1,
49-
"range": [
50-
0,
51-
5
52-
],
5342
"raw": "3 + 4",
43+
"start": 0,
5444
"type": "Program"
5545
}
Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,56 @@
11
{
22
"body": {
33
"column": 1,
4+
"end": 9,
45
"inline": false,
56
"line": 1,
6-
"range": [
7-
0,
8-
9
9-
],
107
"raw": "[1, 2, 3]",
8+
"start": 0,
119
"statements": [
1210
{
1311
"column": 1,
12+
"end": 9,
1413
"line": 1,
1514
"members": [
1615
{
1716
"column": 2,
1817
"data": 1,
18+
"end": 2,
1919
"line": 1,
20-
"range": [
21-
1,
22-
2
23-
],
2420
"raw": "1",
21+
"start": 1,
2522
"type": "Int"
2623
},
2724
{
2825
"column": 5,
2926
"data": 2,
27+
"end": 5,
3028
"line": 1,
31-
"range": [
32-
4,
33-
5
34-
],
3529
"raw": "2",
30+
"start": 4,
3631
"type": "Int"
3732
},
3833
{
3934
"column": 8,
4035
"data": 3,
36+
"end": 8,
4137
"line": 1,
42-
"range": [
43-
7,
44-
8
45-
],
4638
"raw": "3",
39+
"start": 7,
4740
"type": "Int"
4841
}
4942
],
50-
"range": [
51-
0,
52-
9
53-
],
5443
"raw": "[1, 2, 3]",
44+
"start": 0,
5545
"type": "ArrayInitialiser"
5646
}
5747
],
5848
"type": "Block"
5949
},
6050
"column": 1,
51+
"end": 9,
6152
"line": 1,
62-
"range": [
63-
0,
64-
9
65-
],
6653
"raw": "[1, 2, 3]",
54+
"start": 0,
6755
"type": "Program"
6856
}
Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,38 @@
11
{
22
"body": {
33
"column": 1,
4+
"end": 3,
45
"inline": false,
56
"line": 1,
6-
"range": [
7-
0,
8-
3
9-
],
107
"raw": "[1]",
8+
"start": 0,
119
"statements": [
1210
{
1311
"column": 1,
12+
"end": 3,
1413
"line": 1,
1514
"members": [
1615
{
1716
"column": 2,
1817
"data": 1,
18+
"end": 2,
1919
"line": 1,
20-
"range": [
21-
1,
22-
2
23-
],
2420
"raw": "1",
21+
"start": 1,
2522
"type": "Int"
2623
}
2724
],
28-
"range": [
29-
0,
30-
3
31-
],
3225
"raw": "[1]",
26+
"start": 0,
3327
"type": "ArrayInitialiser"
3428
}
3529
],
3630
"type": "Block"
3731
},
3832
"column": 1,
33+
"end": 3,
3934
"line": 1,
40-
"range": [
41-
0,
42-
3
43-
],
4435
"raw": "[1]",
36+
"start": 0,
4537
"type": "Program"
4638
}

test/examples/assign/output.json

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,45 @@
11
{
22
"body": {
33
"column": 1,
4+
"end": 5,
45
"inline": false,
56
"line": 1,
6-
"range": [
7-
0,
8-
5
9-
],
107
"raw": "a = 1",
8+
"start": 0,
119
"statements": [
1210
{
1311
"assignee": {
1412
"column": 1,
1513
"data": "a",
14+
"end": 1,
1615
"line": 1,
17-
"range": [
18-
0,
19-
1
20-
],
2116
"raw": "a",
17+
"start": 0,
2218
"type": "Identifier"
2319
},
2420
"column": 1,
21+
"end": 5,
2522
"expression": {
2623
"column": 5,
2724
"data": 1,
25+
"end": 5,
2826
"line": 1,
29-
"range": [
30-
4,
31-
5
32-
],
3327
"raw": "1",
28+
"start": 4,
3429
"type": "Int"
3530
},
3631
"line": 1,
37-
"range": [
38-
0,
39-
5
40-
],
4132
"raw": "a = 1",
33+
"start": 0,
4234
"type": "AssignOp"
4335
}
4436
],
4537
"type": "Block"
4638
},
4739
"column": 1,
40+
"end": 5,
4841
"line": 1,
49-
"range": [
50-
0,
51-
5
52-
],
5342
"raw": "a = 1",
43+
"start": 0,
5444
"type": "Program"
5545
}
Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,28 @@
11
{
22
"body": {
33
"column": 1,
4+
"end": 23,
45
"inline": false,
56
"line": 1,
6-
"range": [
7-
0,
8-
23
9-
],
107
"raw": "`import foo from 'foo'`",
8+
"start": 0,
119
"statements": [
1210
{
1311
"column": 1,
1412
"data": "import foo from 'foo'",
13+
"end": 23,
1514
"line": 1,
16-
"range": [
17-
0,
18-
23
19-
],
2015
"raw": "`import foo from 'foo'`",
16+
"start": 0,
2117
"type": "JavaScript"
2218
}
2319
],
2420
"type": "Block"
2521
},
2622
"column": 1,
23+
"end": 24,
2724
"line": 1,
28-
"range": [
29-
0,
30-
24
31-
],
3225
"raw": "`import foo from 'foo'`\n",
26+
"start": 0,
3327
"type": "Program"
3428
}

0 commit comments

Comments
 (0)