@@ -1,16 +1,8 @@
|
||||
import Exception from "../exception";
|
||||
|
||||
function LocationInfo(locInfo) {
|
||||
locInfo = locInfo || {};
|
||||
this.firstLine = locInfo.first_line;
|
||||
this.firstColumn = locInfo.first_column;
|
||||
this.lastColumn = locInfo.last_column;
|
||||
this.lastLine = locInfo.last_line;
|
||||
}
|
||||
|
||||
var AST = {
|
||||
ProgramNode: function(statements, blockParams, strip, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "program";
|
||||
this.statements = statements;
|
||||
this.blockParams = blockParams;
|
||||
@@ -18,7 +10,7 @@ var AST = {
|
||||
},
|
||||
|
||||
MustacheNode: function(rawParams, hash, open, strip, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "mustache";
|
||||
this.strip = strip;
|
||||
|
||||
@@ -47,7 +39,7 @@ var AST = {
|
||||
},
|
||||
|
||||
SexprNode: function(rawParams, hash, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
|
||||
this.type = "sexpr";
|
||||
this.hash = hash;
|
||||
@@ -70,7 +62,7 @@ var AST = {
|
||||
},
|
||||
|
||||
PartialNode: function(partialName, context, hash, strip, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "partial";
|
||||
this.partialName = partialName;
|
||||
this.context = context;
|
||||
@@ -81,7 +73,7 @@ var AST = {
|
||||
},
|
||||
|
||||
BlockNode: function(sexpr, program, inverse, strip, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
|
||||
this.type = 'block';
|
||||
this.sexpr = sexpr;
|
||||
@@ -95,19 +87,19 @@ var AST = {
|
||||
},
|
||||
|
||||
ContentNode: function(string, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "content";
|
||||
this.original = this.string = string;
|
||||
},
|
||||
|
||||
HashNode: function(pairs, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "hash";
|
||||
this.pairs = pairs;
|
||||
},
|
||||
|
||||
IdNode: function(parts, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "ID";
|
||||
|
||||
var original = "",
|
||||
@@ -147,13 +139,13 @@ var AST = {
|
||||
},
|
||||
|
||||
PartialNameNode: function(name, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "PARTIAL_NAME";
|
||||
this.name = name.original;
|
||||
},
|
||||
|
||||
DataNode: function(id, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "DATA";
|
||||
this.id = id;
|
||||
this.stringModeValue = id.stringModeValue;
|
||||
@@ -161,7 +153,7 @@ var AST = {
|
||||
},
|
||||
|
||||
StringNode: function(string, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "STRING";
|
||||
this.original =
|
||||
this.string =
|
||||
@@ -169,7 +161,7 @@ var AST = {
|
||||
},
|
||||
|
||||
NumberNode: function(number, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "NUMBER";
|
||||
this.original =
|
||||
this.number = number;
|
||||
@@ -177,14 +169,14 @@ var AST = {
|
||||
},
|
||||
|
||||
BooleanNode: function(bool, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "BOOLEAN";
|
||||
this.bool = bool;
|
||||
this.stringModeValue = bool === "true";
|
||||
},
|
||||
|
||||
CommentNode: function(comment, strip, locInfo) {
|
||||
LocationInfo.call(this, locInfo);
|
||||
this.loc = locInfo;
|
||||
this.type = "comment";
|
||||
this.comment = comment;
|
||||
|
||||
|
||||
@@ -8,11 +8,16 @@ export { parser };
|
||||
var yy = {};
|
||||
extend(yy, Helpers, AST);
|
||||
|
||||
export function parse(input) {
|
||||
export function parse(input, options) {
|
||||
// Just return if an already-compile AST was passed in.
|
||||
if (input.constructor === AST.ProgramNode) { return input; }
|
||||
|
||||
parser.yy = yy;
|
||||
|
||||
// Altering the shared object here, but this is ok as parser is a sync operation
|
||||
yy.locInfo = function(locInfo) {
|
||||
return new yy.SourceLocation(options && options.srcName, locInfo);
|
||||
};
|
||||
|
||||
return parser.parse(input);
|
||||
}
|
||||
|
||||
@@ -79,18 +79,18 @@ CodeGen.prototype = {
|
||||
},
|
||||
|
||||
empty: function(loc) {
|
||||
loc = loc || this.currentLocation || {};
|
||||
return new SourceNode(loc.firstLine, loc.firstColumn, this.srcFile);
|
||||
loc = loc || this.currentLocation || {start:{}};
|
||||
return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
|
||||
},
|
||||
wrap: function(chunk, loc) {
|
||||
if (chunk instanceof SourceNode) {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
loc = loc || this.currentLocation || {};
|
||||
loc = loc || this.currentLocation || {start:{}};
|
||||
chunk = castChunk(chunk, this, loc);
|
||||
|
||||
return new SourceNode(loc.firstLine, loc.firstColumn, this.srcFile, chunk);
|
||||
return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
|
||||
},
|
||||
|
||||
functionCall: function(fn, type, params) {
|
||||
|
||||
@@ -298,11 +298,7 @@ Compiler.prototype = {
|
||||
|
||||
// HELPERS
|
||||
opcode: function(name, node) {
|
||||
var loc = {
|
||||
firstLine: node.firstLine, firstColumn: node.firstColumn,
|
||||
lastLine: node.lastLine, lastColumn: node.lastColumn
|
||||
};
|
||||
this.opcodes.push({ opcode: name, args: slice.call(arguments, 2), loc: loc });
|
||||
this.opcodes.push({ opcode: name, args: slice.call(arguments, 2), loc: node.loc });
|
||||
},
|
||||
|
||||
addDepth: function(depth) {
|
||||
@@ -393,7 +389,7 @@ export function precompile(input, options, env) {
|
||||
options.useDepths = true;
|
||||
}
|
||||
|
||||
var ast = env.parse(input);
|
||||
var ast = env.parse(input, options);
|
||||
var environment = new env.Compiler().compile(ast, options);
|
||||
return new env.JavaScriptCompiler().compile(environment, options);
|
||||
}
|
||||
@@ -415,7 +411,7 @@ export function compile(input, options, env) {
|
||||
var compiled;
|
||||
|
||||
function compileInput() {
|
||||
var ast = env.parse(input);
|
||||
var ast = env.parse(input, options);
|
||||
var environment = new env.Compiler().compile(ast, options);
|
||||
var templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
|
||||
return env.template(templateSpec);
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
import Exception from "../exception";
|
||||
|
||||
export function SourceLocation(source, locInfo) {
|
||||
this.source = source;
|
||||
this.start = {
|
||||
line: locInfo.first_line,
|
||||
column: locInfo.first_column
|
||||
};
|
||||
this.end = {
|
||||
line: locInfo.last_line,
|
||||
column: locInfo.last_column
|
||||
};
|
||||
}
|
||||
|
||||
export function stripFlags(open, close) {
|
||||
return {
|
||||
left: open.charAt(2) === '~',
|
||||
@@ -15,10 +27,7 @@ export function stripComment(comment) {
|
||||
export function prepareRawBlock(openRawBlock, content, close, locInfo) {
|
||||
/*jshint -W040 */
|
||||
if (openRawBlock.sexpr.id.original !== close) {
|
||||
var errorNode = {
|
||||
firstLine: openRawBlock.sexpr.firstLine,
|
||||
firstColumn: openRawBlock.sexpr.firstColumn
|
||||
};
|
||||
var errorNode = {loc: openRawBlock.sexpr.loc};
|
||||
|
||||
throw new Exception(openRawBlock.sexpr.id.original + " doesn't match " + close, errorNode);
|
||||
}
|
||||
@@ -32,10 +41,7 @@ export function prepareBlock(openBlock, program, inverseAndProgram, close, inver
|
||||
/*jshint -W040 */
|
||||
// When we are chaining inverse calls, we will not have a close path
|
||||
if (close && close.path && openBlock.sexpr.id.original !== close.path.original) {
|
||||
var errorNode = {
|
||||
firstLine: openBlock.sexpr.firstLine,
|
||||
firstColumn: openBlock.sexpr.firstColumn
|
||||
};
|
||||
var errorNode = {loc: openBlock.sexpr.loc};
|
||||
|
||||
throw new Exception(openBlock.sexpr.id.original + ' doesn\'t match ' + close.path.original, errorNode);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ JavaScriptCompiler.prototype = {
|
||||
if (!asObject) {
|
||||
ret.compiler = JSON.stringify(ret.compiler);
|
||||
|
||||
this.source.currentLocation = {firstLine: 1, firstColumn: 0};
|
||||
this.source.currentLocation = {start: {line: 1, column: 0}};
|
||||
ret = this.objectLiteral(ret);
|
||||
|
||||
if (options.srcName) {
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
|
||||
|
||||
function Exception(message, node) {
|
||||
var line;
|
||||
if (node && node.firstLine) {
|
||||
line = node.firstLine;
|
||||
var loc = node && node.loc,
|
||||
line,
|
||||
column;
|
||||
if (loc) {
|
||||
line = loc.start.line;
|
||||
column = loc.start.column;
|
||||
|
||||
message += ' - ' + line + ':' + node.firstColumn;
|
||||
message += ' - ' + line + ':' + column;
|
||||
}
|
||||
|
||||
var tmp = Error.prototype.constructor.call(this, message);
|
||||
@@ -16,9 +19,9 @@ function Exception(message, node) {
|
||||
this[errorProps[idx]] = tmp[errorProps[idx]];
|
||||
}
|
||||
|
||||
if (line) {
|
||||
if (loc) {
|
||||
this.lineNumber = line;
|
||||
this.column = node.firstColumn;
|
||||
this.column = column;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-20
@@ -5,22 +5,21 @@ describe('ast', function() {
|
||||
}
|
||||
|
||||
var LOCATION_INFO = {
|
||||
last_line: 0,
|
||||
first_line: 0,
|
||||
first_column: 0,
|
||||
last_column: 0
|
||||
start: {
|
||||
line: 1,
|
||||
column: 1
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 1
|
||||
}
|
||||
};
|
||||
|
||||
function testLocationInfoStorage(node){
|
||||
var properties = [ 'firstLine', 'lastLine', 'firstColumn', 'lastColumn' ],
|
||||
property,
|
||||
propertiesLen = properties.length,
|
||||
i;
|
||||
|
||||
for (i = 0; i < propertiesLen; i++){
|
||||
property = properties[0];
|
||||
equals(node[property], 0);
|
||||
}
|
||||
equals(node.loc.start.line, 1);
|
||||
equals(node.loc.start.column, 1);
|
||||
equals(node.loc.end.line, 1);
|
||||
equals(node.loc.end.column, 1);
|
||||
}
|
||||
|
||||
describe('MustacheNode', function() {
|
||||
@@ -94,21 +93,21 @@ describe('ast', function() {
|
||||
{part: 'foo'},
|
||||
{part: '..'},
|
||||
{part: 'bar'}
|
||||
], {first_line: 1, first_column: 1});
|
||||
], {start: {line: 1, column: 1}});
|
||||
}, Handlebars.Exception, "Invalid path: foo.. - 1:1");
|
||||
shouldThrow(function() {
|
||||
new handlebarsEnv.AST.IdNode([
|
||||
{part: 'foo'},
|
||||
{part: '.'},
|
||||
{part: 'bar'}
|
||||
], {first_line: 1, first_column: 1});
|
||||
], {start: {line: 1, column: 1}});
|
||||
}, Handlebars.Exception, "Invalid path: foo. - 1:1");
|
||||
shouldThrow(function() {
|
||||
new handlebarsEnv.AST.IdNode([
|
||||
{part: 'foo'},
|
||||
{part: 'this'},
|
||||
{part: 'bar'}
|
||||
], {first_line: 1, first_column: 1});
|
||||
], {start: {line: 1, column: 1}});
|
||||
}, Handlebars.Exception, "Invalid path: foothis - 1:1");
|
||||
});
|
||||
|
||||
@@ -201,10 +200,10 @@ describe('ast', function() {
|
||||
var ast, statements;
|
||||
|
||||
function testColumns(node, firstLine, lastLine, firstColumn, lastColumn){
|
||||
equals(node.firstLine, firstLine);
|
||||
equals(node.lastLine, lastLine);
|
||||
equals(node.firstColumn, firstColumn);
|
||||
equals(node.lastColumn, lastColumn);
|
||||
equals(node.loc.start.line, firstLine);
|
||||
equals(node.loc.start.column, firstColumn);
|
||||
equals(node.loc.end.line, lastLine);
|
||||
equals(node.loc.end.column, lastColumn);
|
||||
}
|
||||
|
||||
ast = Handlebars.parse("line 1 {{line1Token}}\n line 2 {{line2token}}\n line 3 {{#blockHelperOnLine3}}\nline 4{{line4token}}\n" +
|
||||
|
||||
+24
-24
@@ -9,7 +9,7 @@ root
|
||||
;
|
||||
|
||||
program
|
||||
: statement* -> new yy.ProgramNode(yy.prepareProgram($1), null, {}, @$)
|
||||
: statement* -> new yy.ProgramNode(yy.prepareProgram($1), null, {}, yy.locInfo(@$))
|
||||
;
|
||||
|
||||
statement
|
||||
@@ -18,15 +18,15 @@ statement
|
||||
| rawBlock -> $1
|
||||
| partial -> $1
|
||||
| content -> $1
|
||||
| COMMENT -> new yy.CommentNode(yy.stripComment($1), yy.stripFlags($1, $1), @$)
|
||||
| COMMENT -> new yy.CommentNode(yy.stripComment($1), yy.stripFlags($1, $1), yy.locInfo(@$))
|
||||
;
|
||||
|
||||
content
|
||||
: CONTENT -> new yy.ContentNode($1, @$)
|
||||
: CONTENT -> new yy.ContentNode($1, yy.locInfo(@$))
|
||||
;
|
||||
|
||||
rawBlock
|
||||
: openRawBlock content END_RAW_BLOCK -> yy.prepareRawBlock($1, $2, $3, @$)
|
||||
: openRawBlock content END_RAW_BLOCK -> yy.prepareRawBlock($1, $2, $3, yy.locInfo(@$))
|
||||
;
|
||||
|
||||
openRawBlock
|
||||
@@ -34,8 +34,8 @@ openRawBlock
|
||||
;
|
||||
|
||||
block
|
||||
: openBlock program inverseChain? closeBlock -> yy.prepareBlock($1, $2, $3, $4, false, @$)
|
||||
| openInverse program inverseAndProgram? closeBlock -> yy.prepareBlock($1, $2, $3, $4, true, @$)
|
||||
: openBlock program inverseChain? closeBlock -> yy.prepareBlock($1, $2, $3, $4, false, yy.locInfo(@$))
|
||||
| openInverse program inverseAndProgram? closeBlock -> yy.prepareBlock($1, $2, $3, $4, true, yy.locInfo(@$))
|
||||
;
|
||||
|
||||
openBlock
|
||||
@@ -47,7 +47,7 @@ openInverse
|
||||
;
|
||||
|
||||
openInverseChain
|
||||
: OPEN_INVERSE_CHAIN sexpr CLOSE -> new yy.MustacheNode($2, null, $1, yy.stripFlags($1, $3), @$)
|
||||
: OPEN_INVERSE_CHAIN sexpr CLOSE -> new yy.MustacheNode($2, null, $1, yy.stripFlags($1, $3), yy.locInfo(@$))
|
||||
;
|
||||
|
||||
inverseAndProgram
|
||||
@@ -56,8 +56,8 @@ inverseAndProgram
|
||||
|
||||
inverseChain
|
||||
: openInverseChain program inverseChain? {
|
||||
var inverse = yy.prepareBlock($1, $2, $3, $3, false, @$),
|
||||
program = new yy.ProgramNode(yy.prepareProgram([inverse]), null, {}, @$);
|
||||
var inverse = yy.prepareBlock($1, $2, $3, $3, false, yy.locInfo(@$)),
|
||||
program = new yy.ProgramNode(yy.prepareProgram([inverse]), null, {}, yy.locInfo(@$));
|
||||
|
||||
program.inverse = inverse;
|
||||
|
||||
@@ -73,31 +73,31 @@ closeBlock
|
||||
mustache
|
||||
// Parsing out the '&' escape token at AST level saves ~500 bytes after min due to the removal of one parser node.
|
||||
// This also allows for handler unification as all mustache node instances can utilize the same handler
|
||||
: OPEN sexpr CLOSE -> new yy.MustacheNode($2, null, $1, yy.stripFlags($1, $3), @$)
|
||||
| OPEN_UNESCAPED sexpr CLOSE_UNESCAPED -> new yy.MustacheNode($2, null, $1, yy.stripFlags($1, $3), @$)
|
||||
: OPEN sexpr CLOSE -> new yy.MustacheNode($2, null, $1, yy.stripFlags($1, $3), yy.locInfo(@$))
|
||||
| OPEN_UNESCAPED sexpr CLOSE_UNESCAPED -> new yy.MustacheNode($2, null, $1, yy.stripFlags($1, $3), yy.locInfo(@$))
|
||||
;
|
||||
|
||||
partial
|
||||
: OPEN_PARTIAL partialName param hash? CLOSE -> new yy.PartialNode($2, $3, $4, yy.stripFlags($1, $5), @$)
|
||||
| OPEN_PARTIAL partialName hash? CLOSE -> new yy.PartialNode($2, undefined, $3, yy.stripFlags($1, $4), @$)
|
||||
: OPEN_PARTIAL partialName param hash? CLOSE -> new yy.PartialNode($2, $3, $4, yy.stripFlags($1, $5), yy.locInfo(@$))
|
||||
| OPEN_PARTIAL partialName hash? CLOSE -> new yy.PartialNode($2, undefined, $3, yy.stripFlags($1, $4), yy.locInfo(@$))
|
||||
;
|
||||
|
||||
sexpr
|
||||
: path param* hash? -> new yy.SexprNode([$1].concat($2), $3, @$)
|
||||
| dataName -> new yy.SexprNode([$1], null, @$)
|
||||
: path param* hash? -> new yy.SexprNode([$1].concat($2), $3, yy.locInfo(@$))
|
||||
| dataName -> new yy.SexprNode([$1], null, yy.locInfo(@$))
|
||||
;
|
||||
|
||||
param
|
||||
: path -> $1
|
||||
| STRING -> new yy.StringNode($1, @$)
|
||||
| NUMBER -> new yy.NumberNode($1, @$)
|
||||
| BOOLEAN -> new yy.BooleanNode($1, @$)
|
||||
| STRING -> new yy.StringNode($1, yy.locInfo(@$))
|
||||
| NUMBER -> new yy.NumberNode($1, yy.locInfo(@$))
|
||||
| BOOLEAN -> new yy.BooleanNode($1, yy.locInfo(@$))
|
||||
| dataName -> $1
|
||||
| OPEN_SEXPR sexpr CLOSE_SEXPR {$2.isHelper = true; $$ = $2;}
|
||||
;
|
||||
|
||||
hash
|
||||
: hashSegment+ -> new yy.HashNode($1, @$)
|
||||
: hashSegment+ -> new yy.HashNode($1, yy.locInfo(@$))
|
||||
;
|
||||
|
||||
hashSegment
|
||||
@@ -109,17 +109,17 @@ blockParams
|
||||
;
|
||||
|
||||
partialName
|
||||
: path -> new yy.PartialNameNode($1, @$)
|
||||
| STRING -> new yy.PartialNameNode(new yy.StringNode($1, @$), @$)
|
||||
| NUMBER -> new yy.PartialNameNode(new yy.NumberNode($1, @$))
|
||||
: path -> new yy.PartialNameNode($1, yy.locInfo(@$))
|
||||
| STRING -> new yy.PartialNameNode(new yy.StringNode($1, yy.locInfo(@$)), yy.locInfo(@$))
|
||||
| NUMBER -> new yy.PartialNameNode(new yy.NumberNode($1, yy.locInfo(@$)))
|
||||
;
|
||||
|
||||
dataName
|
||||
: DATA path -> new yy.DataNode($2, @$)
|
||||
: DATA path -> new yy.DataNode($2, yy.locInfo(@$))
|
||||
;
|
||||
|
||||
path
|
||||
: pathSegments -> new yy.IdNode($1, @$)
|
||||
: pathSegments -> new yy.IdNode($1, yy.locInfo(@$))
|
||||
;
|
||||
|
||||
pathSegments
|
||||
|
||||
Reference in New Issue
Block a user