Skip to content

Commit 61dd721

Browse files
committed
Update AST location info to match SpiderMonkey
Part of #889
1 parent 3a9440f commit 61dd721

File tree

9 files changed

+95
-94
lines changed

9 files changed

+95
-94
lines changed

lib/handlebars/compiler/ast.js

+14-22
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
11
import Exception from "../exception";
22

3-
function LocationInfo(locInfo) {
4-
locInfo = locInfo || {};
5-
this.firstLine = locInfo.first_line;
6-
this.firstColumn = locInfo.first_column;
7-
this.lastColumn = locInfo.last_column;
8-
this.lastLine = locInfo.last_line;
9-
}
10-
113
var AST = {
124
ProgramNode: function(statements, blockParams, strip, locInfo) {
13-
LocationInfo.call(this, locInfo);
5+
this.loc = locInfo;
146
this.type = "program";
157
this.statements = statements;
168
this.blockParams = blockParams;
179
this.strip = strip;
1810
},
1911

2012
MustacheNode: function(rawParams, hash, open, strip, locInfo) {
21-
LocationInfo.call(this, locInfo);
13+
this.loc = locInfo;
2214
this.type = "mustache";
2315
this.strip = strip;
2416

@@ -47,7 +39,7 @@ var AST = {
4739
},
4840

4941
SexprNode: function(rawParams, hash, locInfo) {
50-
LocationInfo.call(this, locInfo);
42+
this.loc = locInfo;
5143

5244
this.type = "sexpr";
5345
this.hash = hash;
@@ -70,7 +62,7 @@ var AST = {
7062
},
7163

7264
PartialNode: function(partialName, context, hash, strip, locInfo) {
73-
LocationInfo.call(this, locInfo);
65+
this.loc = locInfo;
7466
this.type = "partial";
7567
this.partialName = partialName;
7668
this.context = context;
@@ -81,7 +73,7 @@ var AST = {
8173
},
8274

8375
BlockNode: function(sexpr, program, inverse, strip, locInfo) {
84-
LocationInfo.call(this, locInfo);
76+
this.loc = locInfo;
8577

8678
this.type = 'block';
8779
this.sexpr = sexpr;
@@ -95,19 +87,19 @@ var AST = {
9587
},
9688

9789
ContentNode: function(string, locInfo) {
98-
LocationInfo.call(this, locInfo);
90+
this.loc = locInfo;
9991
this.type = "content";
10092
this.original = this.string = string;
10193
},
10294

10395
HashNode: function(pairs, locInfo) {
104-
LocationInfo.call(this, locInfo);
96+
this.loc = locInfo;
10597
this.type = "hash";
10698
this.pairs = pairs;
10799
},
108100

109101
IdNode: function(parts, locInfo) {
110-
LocationInfo.call(this, locInfo);
102+
this.loc = locInfo;
111103
this.type = "ID";
112104

113105
var original = "",
@@ -147,44 +139,44 @@ var AST = {
147139
},
148140

149141
PartialNameNode: function(name, locInfo) {
150-
LocationInfo.call(this, locInfo);
142+
this.loc = locInfo;
151143
this.type = "PARTIAL_NAME";
152144
this.name = name.original;
153145
},
154146

155147
DataNode: function(id, locInfo) {
156-
LocationInfo.call(this, locInfo);
148+
this.loc = locInfo;
157149
this.type = "DATA";
158150
this.id = id;
159151
this.stringModeValue = id.stringModeValue;
160152
this.idName = '@' + id.stringModeValue;
161153
},
162154

163155
StringNode: function(string, locInfo) {
164-
LocationInfo.call(this, locInfo);
156+
this.loc = locInfo;
165157
this.type = "STRING";
166158
this.original =
167159
this.string =
168160
this.stringModeValue = string;
169161
},
170162

171163
NumberNode: function(number, locInfo) {
172-
LocationInfo.call(this, locInfo);
164+
this.loc = locInfo;
173165
this.type = "NUMBER";
174166
this.original =
175167
this.number = number;
176168
this.stringModeValue = Number(number);
177169
},
178170

179171
BooleanNode: function(bool, locInfo) {
180-
LocationInfo.call(this, locInfo);
172+
this.loc = locInfo;
181173
this.type = "BOOLEAN";
182174
this.bool = bool;
183175
this.stringModeValue = bool === "true";
184176
},
185177

186178
CommentNode: function(comment, strip, locInfo) {
187-
LocationInfo.call(this, locInfo);
179+
this.loc = locInfo;
188180
this.type = "comment";
189181
this.comment = comment;
190182

lib/handlebars/compiler/base.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@ export { parser };
88
var yy = {};
99
extend(yy, Helpers, AST);
1010

11-
export function parse(input) {
11+
export function parse(input, options) {
1212
// Just return if an already-compile AST was passed in.
1313
if (input.constructor === AST.ProgramNode) { return input; }
1414

1515
parser.yy = yy;
1616

17+
// Altering the shared object here, but this is ok as parser is a sync operation
18+
yy.locInfo = function(locInfo) {
19+
return new yy.SourceLocation(options && options.srcName, locInfo);
20+
};
21+
1722
return parser.parse(input);
1823
}

lib/handlebars/compiler/code-gen.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,18 @@ CodeGen.prototype = {
7979
},
8080

8181
empty: function(loc) {
82-
loc = loc || this.currentLocation || {};
83-
return new SourceNode(loc.firstLine, loc.firstColumn, this.srcFile);
82+
loc = loc || this.currentLocation || {start:{}};
83+
return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
8484
},
8585
wrap: function(chunk, loc) {
8686
if (chunk instanceof SourceNode) {
8787
return chunk;
8888
}
8989

90-
loc = loc || this.currentLocation || {};
90+
loc = loc || this.currentLocation || {start:{}};
9191
chunk = castChunk(chunk, this, loc);
9292

93-
return new SourceNode(loc.firstLine, loc.firstColumn, this.srcFile, chunk);
93+
return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
9494
},
9595

9696
functionCall: function(fn, type, params) {

lib/handlebars/compiler/compiler.js

+3-7
Original file line numberDiff line numberDiff line change
@@ -298,11 +298,7 @@ Compiler.prototype = {
298298

299299
// HELPERS
300300
opcode: function(name, node) {
301-
var loc = {
302-
firstLine: node.firstLine, firstColumn: node.firstColumn,
303-
lastLine: node.lastLine, lastColumn: node.lastColumn
304-
};
305-
this.opcodes.push({ opcode: name, args: slice.call(arguments, 2), loc: loc });
301+
this.opcodes.push({ opcode: name, args: slice.call(arguments, 2), loc: node.loc });
306302
},
307303

308304
addDepth: function(depth) {
@@ -393,7 +389,7 @@ export function precompile(input, options, env) {
393389
options.useDepths = true;
394390
}
395391

396-
var ast = env.parse(input);
392+
var ast = env.parse(input, options);
397393
var environment = new env.Compiler().compile(ast, options);
398394
return new env.JavaScriptCompiler().compile(environment, options);
399395
}
@@ -415,7 +411,7 @@ export function compile(input, options, env) {
415411
var compiled;
416412

417413
function compileInput() {
418-
var ast = env.parse(input);
414+
var ast = env.parse(input, options);
419415
var environment = new env.Compiler().compile(ast, options);
420416
var templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
421417
return env.template(templateSpec);

lib/handlebars/compiler/helpers.js

+14-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
import Exception from "../exception";
22

3+
export function SourceLocation(source, locInfo) {
4+
this.source = source;
5+
this.start = {
6+
line: locInfo.first_line,
7+
column: locInfo.first_column
8+
};
9+
this.end = {
10+
line: locInfo.last_line,
11+
column: locInfo.last_column
12+
};
13+
}
14+
315
export function stripFlags(open, close) {
416
return {
517
left: open.charAt(2) === '~',
@@ -15,10 +27,7 @@ export function stripComment(comment) {
1527
export function prepareRawBlock(openRawBlock, content, close, locInfo) {
1628
/*jshint -W040 */
1729
if (openRawBlock.sexpr.id.original !== close) {
18-
var errorNode = {
19-
firstLine: openRawBlock.sexpr.firstLine,
20-
firstColumn: openRawBlock.sexpr.firstColumn
21-
};
30+
var errorNode = {loc: openRawBlock.sexpr.loc};
2231

2332
throw new Exception(openRawBlock.sexpr.id.original + " doesn't match " + close, errorNode);
2433
}
@@ -32,10 +41,7 @@ export function prepareBlock(openBlock, program, inverseAndProgram, close, inver
3241
/*jshint -W040 */
3342
// When we are chaining inverse calls, we will not have a close path
3443
if (close && close.path && openBlock.sexpr.id.original !== close.path.original) {
35-
var errorNode = {
36-
firstLine: openBlock.sexpr.firstLine,
37-
firstColumn: openBlock.sexpr.firstColumn
38-
};
44+
var errorNode = {loc: openBlock.sexpr.loc};
3945

4046
throw new Exception(openBlock.sexpr.id.original + ' doesn\'t match ' + close.path.original, errorNode);
4147
}

lib/handlebars/compiler/javascript-compiler.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ JavaScriptCompiler.prototype = {
136136
if (!asObject) {
137137
ret.compiler = JSON.stringify(ret.compiler);
138138

139-
this.source.currentLocation = {firstLine: 1, firstColumn: 0};
139+
this.source.currentLocation = {start: {line: 1, column: 0}};
140140
ret = this.objectLiteral(ret);
141141

142142
if (options.srcName) {

lib/handlebars/exception.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
33

44
function Exception(message, node) {
5-
var line;
6-
if (node && node.firstLine) {
7-
line = node.firstLine;
8-
9-
message += ' - ' + line + ':' + node.firstColumn;
5+
var loc = node && node.loc,
6+
line,
7+
column;
8+
if (loc) {
9+
line = loc.start.line;
10+
column = loc.start.column;
11+
12+
message += ' - ' + line + ':' + column;
1013
}
1114

1215
var tmp = Error.prototype.constructor.call(this, message);
@@ -16,9 +19,9 @@ function Exception(message, node) {
1619
this[errorProps[idx]] = tmp[errorProps[idx]];
1720
}
1821

19-
if (line) {
22+
if (loc) {
2023
this.lineNumber = line;
21-
this.column = node.firstColumn;
24+
this.column = column;
2225
}
2326
}
2427

spec/ast.js

+19-20
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,21 @@ describe('ast', function() {
55
}
66

77
var LOCATION_INFO = {
8-
last_line: 0,
9-
first_line: 0,
10-
first_column: 0,
11-
last_column: 0
8+
start: {
9+
line: 1,
10+
column: 1
11+
},
12+
end: {
13+
line: 1,
14+
column: 1
15+
}
1216
};
1317

1418
function testLocationInfoStorage(node){
15-
var properties = [ 'firstLine', 'lastLine', 'firstColumn', 'lastColumn' ],
16-
property,
17-
propertiesLen = properties.length,
18-
i;
19-
20-
for (i = 0; i < propertiesLen; i++){
21-
property = properties[0];
22-
equals(node[property], 0);
23-
}
19+
equals(node.loc.start.line, 1);
20+
equals(node.loc.start.column, 1);
21+
equals(node.loc.end.line, 1);
22+
equals(node.loc.end.column, 1);
2423
}
2524

2625
describe('MustacheNode', function() {
@@ -94,21 +93,21 @@ describe('ast', function() {
9493
{part: 'foo'},
9594
{part: '..'},
9695
{part: 'bar'}
97-
], {first_line: 1, first_column: 1});
96+
], {start: {line: 1, column: 1}});
9897
}, Handlebars.Exception, "Invalid path: foo.. - 1:1");
9998
shouldThrow(function() {
10099
new handlebarsEnv.AST.IdNode([
101100
{part: 'foo'},
102101
{part: '.'},
103102
{part: 'bar'}
104-
], {first_line: 1, first_column: 1});
103+
], {start: {line: 1, column: 1}});
105104
}, Handlebars.Exception, "Invalid path: foo. - 1:1");
106105
shouldThrow(function() {
107106
new handlebarsEnv.AST.IdNode([
108107
{part: 'foo'},
109108
{part: 'this'},
110109
{part: 'bar'}
111-
], {first_line: 1, first_column: 1});
110+
], {start: {line: 1, column: 1}});
112111
}, Handlebars.Exception, "Invalid path: foothis - 1:1");
113112
});
114113

@@ -201,10 +200,10 @@ describe('ast', function() {
201200
var ast, statements;
202201

203202
function testColumns(node, firstLine, lastLine, firstColumn, lastColumn){
204-
equals(node.firstLine, firstLine);
205-
equals(node.lastLine, lastLine);
206-
equals(node.firstColumn, firstColumn);
207-
equals(node.lastColumn, lastColumn);
203+
equals(node.loc.start.line, firstLine);
204+
equals(node.loc.start.column, firstColumn);
205+
equals(node.loc.end.line, lastLine);
206+
equals(node.loc.end.column, lastColumn);
208207
}
209208

210209
ast = Handlebars.parse("line 1 {{line1Token}}\n line 2 {{line2token}}\n line 3 {{#blockHelperOnLine3}}\nline 4{{line4token}}\n" +

0 commit comments

Comments
 (0)