templebars 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +4 -0
- data/lib/templebars/rails/version.rb +2 -2
- data/vendor/assets/javascripts/handlebars.js +771 -499
- data/vendor/assets/javascripts/handlebars.runtime.js +31 -13
- metadata +31 -11
@@ -1,9 +1,11 @@
|
|
1
1
|
// lib/handlebars/base.js
|
2
2
|
|
3
3
|
/*jshint eqnull:true*/
|
4
|
-
|
4
|
+
this.Handlebars = {};
|
5
5
|
|
6
|
-
Handlebars
|
6
|
+
(function(Handlebars) {
|
7
|
+
|
8
|
+
Handlebars.VERSION = "1.0.rc.1";
|
7
9
|
|
8
10
|
Handlebars.helpers = {};
|
9
11
|
Handlebars.partials = {};
|
@@ -42,25 +44,36 @@ Handlebars.registerHelper('blockHelperMissing', function(context, options) {
|
|
42
44
|
return inverse(this);
|
43
45
|
} else if(type === "[object Array]") {
|
44
46
|
if(context.length > 0) {
|
45
|
-
|
46
|
-
ret = ret + fn(context[i]);
|
47
|
-
}
|
47
|
+
return Handlebars.helpers.each(context, options);
|
48
48
|
} else {
|
49
|
-
|
49
|
+
return inverse(this);
|
50
50
|
}
|
51
|
-
return ret;
|
52
51
|
} else {
|
53
52
|
return fn(context);
|
54
53
|
}
|
55
54
|
});
|
56
55
|
|
56
|
+
Handlebars.K = function() {};
|
57
|
+
|
58
|
+
Handlebars.createFrame = Object.create || function(object) {
|
59
|
+
Handlebars.K.prototype = object;
|
60
|
+
var obj = new Handlebars.K();
|
61
|
+
Handlebars.K.prototype = null;
|
62
|
+
return obj;
|
63
|
+
};
|
64
|
+
|
57
65
|
Handlebars.registerHelper('each', function(context, options) {
|
58
66
|
var fn = options.fn, inverse = options.inverse;
|
59
|
-
var ret = "";
|
67
|
+
var ret = "", data;
|
68
|
+
|
69
|
+
if (options.data) {
|
70
|
+
data = Handlebars.createFrame(options.data);
|
71
|
+
}
|
60
72
|
|
61
73
|
if(context && context.length > 0) {
|
62
74
|
for(var i=0, j=context.length; i<j; i++) {
|
63
|
-
|
75
|
+
if (data) { data.index = i; }
|
76
|
+
ret = ret + fn(context[i], { data: data });
|
64
77
|
}
|
65
78
|
} else {
|
66
79
|
ret = inverse(this);
|
@@ -94,15 +107,17 @@ Handlebars.registerHelper('with', function(context, options) {
|
|
94
107
|
Handlebars.registerHelper('log', function(context) {
|
95
108
|
Handlebars.log(context);
|
96
109
|
});
|
110
|
+
|
111
|
+
}(this.Handlebars));
|
97
112
|
;
|
98
113
|
// lib/handlebars/compiler/parser.js
|
99
114
|
/* Jison generated parser */
|
100
115
|
var handlebars = (function(){
|
101
116
|
var parser = {trace: function trace() { },
|
102
117
|
yy: {},
|
103
|
-
symbols_: {"error":2,"root":3,"program":4,"EOF":5,"statements":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"OPEN_PARTIAL":24,"params":25,"hash":26,"
|
104
|
-
terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",
|
105
|
-
productions_: [0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[25,2],[25,1],[
|
118
|
+
symbols_: {"error":2,"root":3,"program":4,"EOF":5,"statements":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"OPEN_PARTIAL":24,"params":25,"hash":26,"DATA":27,"param":28,"STRING":29,"INTEGER":30,"BOOLEAN":31,"hashSegments":32,"hashSegment":33,"ID":34,"EQUALS":35,"pathSegments":36,"SEP":37,"$accept":0,"$end":1},
|
119
|
+
terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",27:"DATA",29:"STRING",30:"INTEGER",31:"BOOLEAN",34:"ID",35:"EQUALS",37:"SEP"},
|
120
|
+
productions_: [0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[17,1],[25,2],[25,1],[28,1],[28,1],[28,1],[28,1],[28,1],[26,1],[32,2],[32,1],[33,3],[33,3],[33,3],[33,3],[33,3],[21,1],[36,3],[36,1]],
|
106
121
|
performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
|
107
122
|
|
108
123
|
var $0 = $$.length - 1;
|
@@ -119,9 +134,9 @@ case 5: this.$ = [$$[$0]];
|
|
119
134
|
break;
|
120
135
|
case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
121
136
|
break;
|
122
|
-
case 7: this.$ = new yy.
|
137
|
+
case 7: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]);
|
123
138
|
break;
|
124
|
-
case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0]);
|
139
|
+
case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]);
|
125
140
|
break;
|
126
141
|
case 9: this.$ = $$[$0];
|
127
142
|
break;
|
@@ -155,235 +170,161 @@ case 23: this.$ = [[$$[$0-1]], $$[$0]];
|
|
155
170
|
break;
|
156
171
|
case 24: this.$ = [[$$[$0]], null];
|
157
172
|
break;
|
158
|
-
case 25:
|
173
|
+
case 25: this.$ = [[new yy.DataNode($$[$0])], null];
|
159
174
|
break;
|
160
|
-
case 26: this.$ =
|
175
|
+
case 26: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
161
176
|
break;
|
162
|
-
case 27: this.$ = $$[$0];
|
177
|
+
case 27: this.$ = [$$[$0]];
|
163
178
|
break;
|
164
|
-
case 28: this.$ =
|
179
|
+
case 28: this.$ = $$[$0];
|
165
180
|
break;
|
166
|
-
case 29: this.$ = new yy.
|
181
|
+
case 29: this.$ = new yy.StringNode($$[$0]);
|
167
182
|
break;
|
168
|
-
case 30: this.$ = new yy.
|
183
|
+
case 30: this.$ = new yy.IntegerNode($$[$0]);
|
169
184
|
break;
|
170
|
-
case 31: this.$ = new yy.
|
185
|
+
case 31: this.$ = new yy.BooleanNode($$[$0]);
|
171
186
|
break;
|
172
|
-
case 32:
|
187
|
+
case 32: this.$ = new yy.DataNode($$[$0]);
|
173
188
|
break;
|
174
|
-
case 33: this.$ =
|
189
|
+
case 33: this.$ = new yy.HashNode($$[$0]);
|
175
190
|
break;
|
176
|
-
case 34:
|
191
|
+
case 34: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
177
192
|
break;
|
178
|
-
case 35: this.$ = [$$[$0
|
193
|
+
case 35: this.$ = [$$[$0]];
|
179
194
|
break;
|
180
|
-
case 36: this.$ = [$$[$0-2],
|
195
|
+
case 36: this.$ = [$$[$0-2], $$[$0]];
|
181
196
|
break;
|
182
|
-
case 37: this.$ = [$$[$0-2], new yy.
|
197
|
+
case 37: this.$ = [$$[$0-2], new yy.StringNode($$[$0])];
|
183
198
|
break;
|
184
|
-
case 38: this.$ = new yy.
|
199
|
+
case 38: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])];
|
185
200
|
break;
|
186
|
-
case 39: $$[$0-2].
|
201
|
+
case 39: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])];
|
187
202
|
break;
|
188
|
-
case 40: this.$ = [$$[$0]];
|
203
|
+
case 40: this.$ = [$$[$0-2], new yy.DataNode($$[$0])];
|
204
|
+
break;
|
205
|
+
case 41: this.$ = new yy.IdNode($$[$0]);
|
206
|
+
break;
|
207
|
+
case 42: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
|
208
|
+
break;
|
209
|
+
case 43: this.$ = [$$[$0]];
|
189
210
|
break;
|
190
211
|
}
|
191
212
|
},
|
192
|
-
table: [{3:1,4:2,5:[2,4],6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{1:[3]},{5:[1,16]},{5:[2,3],7:17,8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,19],20:[2,3],22:[1,13],23:[1,14],24:[1,15]},{5:[2,5],14:[2,5],15:[2,5],16:[2,5],19:[2,5],20:[2,5],22:[2,5],23:[2,5],24:[2,5]},{4:20,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{4:21,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{17:22,21:23,
|
193
|
-
defaultActions: {16:[2,1],
|
213
|
+
table: [{3:1,4:2,5:[2,4],6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{1:[3]},{5:[1,16]},{5:[2,3],7:17,8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,19],20:[2,3],22:[1,13],23:[1,14],24:[1,15]},{5:[2,5],14:[2,5],15:[2,5],16:[2,5],19:[2,5],20:[2,5],22:[2,5],23:[2,5],24:[2,5]},{4:20,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{4:21,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{17:22,21:23,27:[1,24],34:[1,26],36:25},{17:27,21:23,27:[1,24],34:[1,26],36:25},{17:28,21:23,27:[1,24],34:[1,26],36:25},{17:29,21:23,27:[1,24],34:[1,26],36:25},{21:30,34:[1,26],36:25},{1:[2,1]},{6:31,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{5:[2,6],14:[2,6],15:[2,6],16:[2,6],19:[2,6],20:[2,6],22:[2,6],23:[2,6],24:[2,6]},{17:22,18:[1,32],21:23,27:[1,24],34:[1,26],36:25},{10:33,20:[1,34]},{10:35,20:[1,34]},{18:[1,36]},{18:[2,24],21:41,25:37,26:38,27:[1,45],28:39,29:[1,42],30:[1,43],31:[1,44],32:40,33:46,34:[1,47],36:25},{18:[2,25]},{18:[2,41],27:[2,41],29:[2,41],30:[2,41],31:[2,41],34:[2,41],37:[1,48]},{18:[2,43],27:[2,43],29:[2,43],30:[2,43],31:[2,43],34:[2,43],37:[2,43]},{18:[1,49]},{18:[1,50]},{18:[1,51]},{18:[1,52],21:53,34:[1,26],36:25},{5:[2,2],8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,2],22:[1,13],23:[1,14],24:[1,15]},{14:[2,20],15:[2,20],16:[2,20],19:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,7],14:[2,7],15:[2,7],16:[2,7],19:[2,7],20:[2,7],22:[2,7],23:[2,7],24:[2,7]},{21:54,34:[1,26],36:25},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],24:[2,8]},{14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{18:[2,22],21:41,26:55,27:[1,45],28:56,29:[1,42],30:[1,43],31:[1,44],32:40,33:46,34:[1,47],36:25},{18:[2,23]},{18:[2,27],27:[2,27],29:[2,27],30:[2,27],31:[2,27],34:[2,27]},{18:[2,33],33:57,34:[1,58]},{18:[2,28],27:[2,28],29:[2,28],30:[2,28],31:[2,28],34:[2,28]},{18:[2,29],27:[2,29],29:[2,29],30:[2,29],31:[2,29],34:[2,29]},{18:[2,30],27:[2,30],29:[2,30],30:[2,30],31:[2,30],34:[2,30]},{18:[2,31],27:[2,31],29:[2,31],30:[2,31],31:[2,31],34:[2,31]},{18:[2,32],27:[2,32],29:[2,32],30:[2,32],31:[2,32],34:[2,32]},{18:[2,35],34:[2,35]},{18:[2,43],27:[2,43],29:[2,43],30:[2,43],31:[2,43],34:[2,43],35:[1,59],37:[2,43]},{34:[1,60]},{14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],24:[2,13]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],24:[2,16]},{5:[2,17],14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],24:[2,18]},{18:[1,61]},{18:[1,62]},{18:[2,21]},{18:[2,26],27:[2,26],29:[2,26],30:[2,26],31:[2,26],34:[2,26]},{18:[2,34],34:[2,34]},{35:[1,59]},{21:63,27:[1,67],29:[1,64],30:[1,65],31:[1,66],34:[1,26],36:25},{18:[2,42],27:[2,42],29:[2,42],30:[2,42],31:[2,42],34:[2,42],37:[2,42]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],24:[2,19]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],24:[2,15]},{18:[2,36],34:[2,36]},{18:[2,37],34:[2,37]},{18:[2,38],34:[2,38]},{18:[2,39],34:[2,39]},{18:[2,40],34:[2,40]}],
|
214
|
+
defaultActions: {16:[2,1],24:[2,25],38:[2,23],55:[2,21]},
|
194
215
|
parseError: function parseError(str, hash) {
|
195
216
|
throw new Error(str);
|
196
217
|
},
|
197
218
|
parse: function parse(input) {
|
198
|
-
var self = this,
|
199
|
-
stack = [0],
|
200
|
-
vstack = [null], // semantic value stack
|
201
|
-
lstack = [], // location stack
|
202
|
-
table = this.table,
|
203
|
-
yytext = '',
|
204
|
-
yylineno = 0,
|
205
|
-
yyleng = 0,
|
206
|
-
recovering = 0,
|
207
|
-
TERROR = 2,
|
208
|
-
EOF = 1;
|
209
|
-
|
210
|
-
//this.reductionCount = this.shiftCount = 0;
|
211
|
-
|
219
|
+
var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
|
212
220
|
this.lexer.setInput(input);
|
213
221
|
this.lexer.yy = this.yy;
|
214
222
|
this.yy.lexer = this.lexer;
|
215
|
-
|
223
|
+
this.yy.parser = this;
|
224
|
+
if (typeof this.lexer.yylloc == "undefined")
|
216
225
|
this.lexer.yylloc = {};
|
217
226
|
var yyloc = this.lexer.yylloc;
|
218
227
|
lstack.push(yyloc);
|
219
|
-
|
220
|
-
if (typeof this.yy.parseError ===
|
228
|
+
var ranges = this.lexer.options && this.lexer.options.ranges;
|
229
|
+
if (typeof this.yy.parseError === "function")
|
221
230
|
this.parseError = this.yy.parseError;
|
222
|
-
|
223
|
-
|
224
|
-
stack.length = stack.length - 2*n;
|
231
|
+
function popStack(n) {
|
232
|
+
stack.length = stack.length - 2 * n;
|
225
233
|
vstack.length = vstack.length - n;
|
226
234
|
lstack.length = lstack.length - n;
|
227
235
|
}
|
228
|
-
|
229
236
|
function lex() {
|
230
237
|
var token;
|
231
|
-
token = self.lexer.lex() || 1;
|
232
|
-
|
233
|
-
if (typeof token !== 'number') {
|
238
|
+
token = self.lexer.lex() || 1;
|
239
|
+
if (typeof token !== "number") {
|
234
240
|
token = self.symbols_[token] || token;
|
235
241
|
}
|
236
242
|
return token;
|
237
243
|
}
|
238
|
-
|
239
|
-
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
|
244
|
+
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
|
240
245
|
while (true) {
|
241
|
-
|
242
|
-
state = stack[stack.length-1];
|
243
|
-
|
244
|
-
// use default actions if available
|
246
|
+
state = stack[stack.length - 1];
|
245
247
|
if (this.defaultActions[state]) {
|
246
248
|
action = this.defaultActions[state];
|
247
249
|
} else {
|
248
|
-
if (symbol ==
|
250
|
+
if (symbol === null || typeof symbol == "undefined") {
|
249
251
|
symbol = lex();
|
250
|
-
|
252
|
+
}
|
251
253
|
action = table[state] && table[state][symbol];
|
252
254
|
}
|
253
|
-
|
254
|
-
|
255
|
-
_handle_error:
|
256
|
-
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
257
|
-
|
255
|
+
if (typeof action === "undefined" || !action.length || !action[0]) {
|
256
|
+
var errStr = "";
|
258
257
|
if (!recovering) {
|
259
|
-
// Report error
|
260
258
|
expected = [];
|
261
|
-
for (p in table[state])
|
262
|
-
|
263
|
-
|
264
|
-
|
259
|
+
for (p in table[state])
|
260
|
+
if (this.terminals_[p] && p > 2) {
|
261
|
+
expected.push("'" + this.terminals_[p] + "'");
|
262
|
+
}
|
265
263
|
if (this.lexer.showPosition) {
|
266
|
-
errStr =
|
264
|
+
errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
|
267
265
|
} else {
|
268
|
-
errStr =
|
269
|
-
(symbol == 1 /*EOF*/ ? "end of input" :
|
270
|
-
("'"+(this.terminals_[symbol] || symbol)+"'"));
|
266
|
+
errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'");
|
271
267
|
}
|
272
|
-
this.parseError(errStr,
|
273
|
-
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
268
|
+
this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
274
269
|
}
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
270
|
+
}
|
271
|
+
if (action[0] instanceof Array && action.length > 1) {
|
272
|
+
throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
|
273
|
+
}
|
274
|
+
switch (action[0]) {
|
275
|
+
case 1:
|
276
|
+
stack.push(symbol);
|
277
|
+
vstack.push(this.lexer.yytext);
|
278
|
+
lstack.push(this.lexer.yylloc);
|
279
|
+
stack.push(action[1]);
|
280
|
+
symbol = null;
|
281
|
+
if (!preErrorSymbol) {
|
283
282
|
yyleng = this.lexer.yyleng;
|
284
283
|
yytext = this.lexer.yytext;
|
285
284
|
yylineno = this.lexer.yylineno;
|
286
285
|
yyloc = this.lexer.yylloc;
|
287
|
-
|
286
|
+
if (recovering > 0)
|
287
|
+
recovering--;
|
288
|
+
} else {
|
289
|
+
symbol = preErrorSymbol;
|
290
|
+
preErrorSymbol = null;
|
288
291
|
}
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
if (state == 0) {
|
297
|
-
throw new Error(errStr || 'Parsing halted.');
|
298
|
-
}
|
299
|
-
popStack(1);
|
300
|
-
state = stack[stack.length-1];
|
292
|
+
break;
|
293
|
+
case 2:
|
294
|
+
len = this.productions_[action[1]][1];
|
295
|
+
yyval.$ = vstack[vstack.length - len];
|
296
|
+
yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column};
|
297
|
+
if (ranges) {
|
298
|
+
yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
|
301
299
|
}
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
stack.push(symbol);
|
321
|
-
vstack.push(this.lexer.yytext);
|
322
|
-
lstack.push(this.lexer.yylloc);
|
323
|
-
stack.push(action[1]); // push state
|
324
|
-
symbol = null;
|
325
|
-
if (!preErrorSymbol) { // normal execution/no error
|
326
|
-
yyleng = this.lexer.yyleng;
|
327
|
-
yytext = this.lexer.yytext;
|
328
|
-
yylineno = this.lexer.yylineno;
|
329
|
-
yyloc = this.lexer.yylloc;
|
330
|
-
if (recovering > 0)
|
331
|
-
recovering--;
|
332
|
-
} else { // error just occurred, resume old lookahead f/ before error
|
333
|
-
symbol = preErrorSymbol;
|
334
|
-
preErrorSymbol = null;
|
335
|
-
}
|
336
|
-
break;
|
337
|
-
|
338
|
-
case 2: // reduce
|
339
|
-
//this.reductionCount++;
|
340
|
-
|
341
|
-
len = this.productions_[action[1]][1];
|
342
|
-
|
343
|
-
// perform semantic action
|
344
|
-
yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
|
345
|
-
// default location, uses first token for firsts, last for lasts
|
346
|
-
yyval._$ = {
|
347
|
-
first_line: lstack[lstack.length-(len||1)].first_line,
|
348
|
-
last_line: lstack[lstack.length-1].last_line,
|
349
|
-
first_column: lstack[lstack.length-(len||1)].first_column,
|
350
|
-
last_column: lstack[lstack.length-1].last_column
|
351
|
-
};
|
352
|
-
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
|
353
|
-
|
354
|
-
if (typeof r !== 'undefined') {
|
355
|
-
return r;
|
356
|
-
}
|
357
|
-
|
358
|
-
// pop off stack
|
359
|
-
if (len) {
|
360
|
-
stack = stack.slice(0,-1*len*2);
|
361
|
-
vstack = vstack.slice(0, -1*len);
|
362
|
-
lstack = lstack.slice(0, -1*len);
|
363
|
-
}
|
364
|
-
|
365
|
-
stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
|
366
|
-
vstack.push(yyval.$);
|
367
|
-
lstack.push(yyval._$);
|
368
|
-
// goto new state = table[STATE][NONTERMINAL]
|
369
|
-
newState = table[stack[stack.length-2]][stack[stack.length-1]];
|
370
|
-
stack.push(newState);
|
371
|
-
break;
|
372
|
-
|
373
|
-
case 3: // accept
|
374
|
-
return true;
|
300
|
+
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
|
301
|
+
if (typeof r !== "undefined") {
|
302
|
+
return r;
|
303
|
+
}
|
304
|
+
if (len) {
|
305
|
+
stack = stack.slice(0, -1 * len * 2);
|
306
|
+
vstack = vstack.slice(0, -1 * len);
|
307
|
+
lstack = lstack.slice(0, -1 * len);
|
308
|
+
}
|
309
|
+
stack.push(this.productions_[action[1]][0]);
|
310
|
+
vstack.push(yyval.$);
|
311
|
+
lstack.push(yyval._$);
|
312
|
+
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
|
313
|
+
stack.push(newState);
|
314
|
+
break;
|
315
|
+
case 3:
|
316
|
+
return true;
|
375
317
|
}
|
376
|
-
|
377
318
|
}
|
378
|
-
|
379
319
|
return true;
|
380
|
-
}
|
320
|
+
}
|
321
|
+
};
|
381
322
|
/* Jison generated lexer */
|
382
323
|
var lexer = (function(){
|
383
324
|
var lexer = ({EOF:1,
|
384
325
|
parseError:function parseError(str, hash) {
|
385
|
-
if (this.yy.
|
386
|
-
this.yy.parseError(str, hash);
|
326
|
+
if (this.yy.parser) {
|
327
|
+
this.yy.parser.parseError(str, hash);
|
387
328
|
} else {
|
388
329
|
throw new Error(str);
|
389
330
|
}
|
@@ -395,27 +336,64 @@ setInput:function (input) {
|
|
395
336
|
this.yytext = this.matched = this.match = '';
|
396
337
|
this.conditionStack = ['INITIAL'];
|
397
338
|
this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
|
339
|
+
if (this.options.ranges) this.yylloc.range = [0,0];
|
340
|
+
this.offset = 0;
|
398
341
|
return this;
|
399
342
|
},
|
400
343
|
input:function () {
|
401
344
|
var ch = this._input[0];
|
402
|
-
this.yytext+=ch;
|
345
|
+
this.yytext += ch;
|
403
346
|
this.yyleng++;
|
404
|
-
this.
|
405
|
-
this.
|
406
|
-
|
407
|
-
|
347
|
+
this.offset++;
|
348
|
+
this.match += ch;
|
349
|
+
this.matched += ch;
|
350
|
+
var lines = ch.match(/(?:\r\n?|\n).*/g);
|
351
|
+
if (lines) {
|
352
|
+
this.yylineno++;
|
353
|
+
this.yylloc.last_line++;
|
354
|
+
} else {
|
355
|
+
this.yylloc.last_column++;
|
356
|
+
}
|
357
|
+
if (this.options.ranges) this.yylloc.range[1]++;
|
358
|
+
|
408
359
|
this._input = this._input.slice(1);
|
409
360
|
return ch;
|
410
361
|
},
|
411
362
|
unput:function (ch) {
|
363
|
+
var len = ch.length;
|
364
|
+
var lines = ch.split(/(?:\r\n?|\n)/g);
|
365
|
+
|
412
366
|
this._input = ch + this._input;
|
367
|
+
this.yytext = this.yytext.substr(0, this.yytext.length-len-1);
|
368
|
+
//this.yyleng -= len;
|
369
|
+
this.offset -= len;
|
370
|
+
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
|
371
|
+
this.match = this.match.substr(0, this.match.length-1);
|
372
|
+
this.matched = this.matched.substr(0, this.matched.length-1);
|
373
|
+
|
374
|
+
if (lines.length-1) this.yylineno -= lines.length-1;
|
375
|
+
var r = this.yylloc.range;
|
376
|
+
|
377
|
+
this.yylloc = {first_line: this.yylloc.first_line,
|
378
|
+
last_line: this.yylineno+1,
|
379
|
+
first_column: this.yylloc.first_column,
|
380
|
+
last_column: lines ?
|
381
|
+
(lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length:
|
382
|
+
this.yylloc.first_column - len
|
383
|
+
};
|
384
|
+
|
385
|
+
if (this.options.ranges) {
|
386
|
+
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
|
387
|
+
}
|
413
388
|
return this;
|
414
389
|
},
|
415
390
|
more:function () {
|
416
391
|
this._more = true;
|
417
392
|
return this;
|
418
393
|
},
|
394
|
+
less:function (n) {
|
395
|
+
this.unput(this.match.slice(n));
|
396
|
+
},
|
419
397
|
pastInput:function () {
|
420
398
|
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
421
399
|
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
|
@@ -458,26 +436,31 @@ next:function () {
|
|
458
436
|
}
|
459
437
|
}
|
460
438
|
if (match) {
|
461
|
-
lines = match[0].match(
|
439
|
+
lines = match[0].match(/(?:\r\n?|\n).*/g);
|
462
440
|
if (lines) this.yylineno += lines.length;
|
463
441
|
this.yylloc = {first_line: this.yylloc.last_line,
|
464
442
|
last_line: this.yylineno+1,
|
465
443
|
first_column: this.yylloc.last_column,
|
466
|
-
last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
|
444
|
+
last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length};
|
467
445
|
this.yytext += match[0];
|
468
446
|
this.match += match[0];
|
447
|
+
this.matches = match;
|
469
448
|
this.yyleng = this.yytext.length;
|
449
|
+
if (this.options.ranges) {
|
450
|
+
this.yylloc.range = [this.offset, this.offset += this.yyleng];
|
451
|
+
}
|
470
452
|
this._more = false;
|
471
453
|
this._input = this._input.slice(match[0].length);
|
472
454
|
this.matched += match[0];
|
473
455
|
token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);
|
456
|
+
if (this.done && this._input) this.done = false;
|
474
457
|
if (token) return token;
|
475
458
|
else return;
|
476
459
|
}
|
477
460
|
if (this._input === "") {
|
478
461
|
return this.EOF;
|
479
462
|
} else {
|
480
|
-
this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
|
463
|
+
return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
|
481
464
|
{text: "", token: null, line: this.yylineno});
|
482
465
|
}
|
483
466
|
},
|
@@ -517,7 +500,11 @@ case 0:
|
|
517
500
|
break;
|
518
501
|
case 1: return 14;
|
519
502
|
break;
|
520
|
-
case 2:
|
503
|
+
case 2:
|
504
|
+
if(yy_.yytext.slice(-1) !== "\\") this.popState();
|
505
|
+
if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1);
|
506
|
+
return 14;
|
507
|
+
|
521
508
|
break;
|
522
509
|
case 3: return 24;
|
523
510
|
break;
|
@@ -537,13 +524,13 @@ case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return
|
|
537
524
|
break;
|
538
525
|
case 11: return 22;
|
539
526
|
break;
|
540
|
-
case 12: return
|
527
|
+
case 12: return 35;
|
541
528
|
break;
|
542
|
-
case 13: return
|
529
|
+
case 13: return 34;
|
543
530
|
break;
|
544
|
-
case 14: return
|
531
|
+
case 14: return 34;
|
545
532
|
break;
|
546
|
-
case 15: return
|
533
|
+
case 15: return 37;
|
547
534
|
break;
|
548
535
|
case 16: /*ignore whitespace*/
|
549
536
|
break;
|
@@ -551,41 +538,47 @@ case 17: this.popState(); return 18;
|
|
551
538
|
break;
|
552
539
|
case 18: this.popState(); return 18;
|
553
540
|
break;
|
554
|
-
case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return
|
541
|
+
case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29;
|
555
542
|
break;
|
556
|
-
case 20: return
|
543
|
+
case 20: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29;
|
557
544
|
break;
|
558
|
-
case 21: return
|
545
|
+
case 21: yy_.yytext = yy_.yytext.substr(1); return 27;
|
559
546
|
break;
|
560
|
-
case 22: return
|
547
|
+
case 22: return 31;
|
561
548
|
break;
|
562
|
-
case 23: return
|
549
|
+
case 23: return 31;
|
563
550
|
break;
|
564
|
-
case 24:
|
551
|
+
case 24: return 30;
|
565
552
|
break;
|
566
|
-
case 25: return
|
553
|
+
case 25: return 34;
|
567
554
|
break;
|
568
|
-
case 26: return
|
555
|
+
case 26: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 34;
|
556
|
+
break;
|
557
|
+
case 27: return 'INVALID';
|
558
|
+
break;
|
559
|
+
case 28: return 5;
|
569
560
|
break;
|
570
561
|
}
|
571
562
|
};
|
572
|
-
lexer.rules = [/^[^\x00]*?(?=(\{\{))/,/^[^\x00]
|
573
|
-
lexer.conditions = {"mu":{"rules":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,
|
563
|
+
lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/];
|
564
|
+
lexer.conditions = {"mu":{"rules":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,28],"inclusive":true}};
|
574
565
|
return lexer;})()
|
575
566
|
parser.lexer = lexer;
|
576
|
-
|
567
|
+
function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;
|
568
|
+
return new Parser;
|
577
569
|
})();
|
578
570
|
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
579
571
|
exports.parser = handlebars;
|
572
|
+
exports.Parser = handlebars.Parser;
|
580
573
|
exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); }
|
581
574
|
exports.main = function commonjsMain(args) {
|
582
575
|
if (!args[1])
|
583
576
|
throw new Error('Usage: '+args[0]+' FILE');
|
577
|
+
var source, cwd;
|
584
578
|
if (typeof process !== 'undefined') {
|
585
|
-
|
579
|
+
source = require('fs').readFileSync(require('path').resolve(args[1]), "utf8");
|
586
580
|
} else {
|
587
|
-
|
588
|
-
var source = cwd.join(args[1]).read({charset: "utf-8"});
|
581
|
+
source = require("file").path(require("file").cwd()).join(args[1]).read({charset: "utf-8"});
|
589
582
|
}
|
590
583
|
return exports.parser.parse(source);
|
591
584
|
}
|
@@ -626,12 +619,26 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
|
|
626
619
|
if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
|
627
620
|
};
|
628
621
|
|
629
|
-
Handlebars.AST.MustacheNode = function(
|
622
|
+
Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
|
630
623
|
this.type = "mustache";
|
631
|
-
this.id = params[0];
|
632
|
-
this.params = params.slice(1);
|
633
|
-
this.hash = hash;
|
634
624
|
this.escaped = !unescaped;
|
625
|
+
this.hash = hash;
|
626
|
+
|
627
|
+
var id = this.id = rawParams[0];
|
628
|
+
var params = this.params = rawParams.slice(1);
|
629
|
+
|
630
|
+
// a mustache is an eligible helper if:
|
631
|
+
// * its id is simple (a single part, not `this` or `..`)
|
632
|
+
var eligibleHelper = this.eligibleHelper = id.isSimple;
|
633
|
+
|
634
|
+
// a mustache is definitely a helper if:
|
635
|
+
// * it is an eligible helper, and
|
636
|
+
// * it has at least one parameter or hash segment
|
637
|
+
this.isHelper = eligibleHelper && (params.length || hash);
|
638
|
+
|
639
|
+
// if a mustache is an eligible helper but not a definite
|
640
|
+
// helper, it is ambiguous, and will be resolved in a later
|
641
|
+
// pass or at runtime.
|
635
642
|
};
|
636
643
|
|
637
644
|
Handlebars.AST.PartialNode = function(id, context) {
|
@@ -649,18 +656,16 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
|
|
649
656
|
}
|
650
657
|
};
|
651
658
|
|
652
|
-
Handlebars.AST.BlockNode = function(mustache, program, close) {
|
659
|
+
Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
|
653
660
|
verifyMatch(mustache.id, close);
|
654
661
|
this.type = "block";
|
655
662
|
this.mustache = mustache;
|
656
663
|
this.program = program;
|
657
|
-
|
664
|
+
this.inverse = inverse;
|
658
665
|
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
this.mustache = mustache;
|
663
|
-
this.program = program;
|
666
|
+
if (this.inverse && !this.program) {
|
667
|
+
this.isInverse = true;
|
668
|
+
}
|
664
669
|
};
|
665
670
|
|
666
671
|
Handlebars.AST.ContentNode = function(string) {
|
@@ -690,7 +695,15 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
|
|
690
695
|
this.parts = dig;
|
691
696
|
this.string = dig.join('.');
|
692
697
|
this.depth = depth;
|
693
|
-
|
698
|
+
|
699
|
+
// an ID is simple if it only has one part, and that part is not
|
700
|
+
// `..` or `this`.
|
701
|
+
this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
|
702
|
+
};
|
703
|
+
|
704
|
+
Handlebars.AST.DataNode = function(id) {
|
705
|
+
this.type = "DATA";
|
706
|
+
this.id = id;
|
694
707
|
};
|
695
708
|
|
696
709
|
Handlebars.AST.StringNode = function(string) {
|
@@ -736,6 +749,7 @@ Handlebars.SafeString.prototype.toString = function() {
|
|
736
749
|
|
737
750
|
(function() {
|
738
751
|
var escape = {
|
752
|
+
"&": "&",
|
739
753
|
"<": "<",
|
740
754
|
">": ">",
|
741
755
|
'"': """,
|
@@ -743,7 +757,7 @@ Handlebars.SafeString.prototype.toString = function() {
|
|
743
757
|
"`": "`"
|
744
758
|
};
|
745
759
|
|
746
|
-
var badChars =
|
760
|
+
var badChars = /[&<>"'`]/g;
|
747
761
|
var possible = /[&<>"'`]/;
|
748
762
|
|
749
763
|
var escapeChar = function(chr) {
|
@@ -785,84 +799,32 @@ Handlebars.Compiler = function() {};
|
|
785
799
|
Handlebars.JavaScriptCompiler = function() {};
|
786
800
|
|
787
801
|
(function(Compiler, JavaScriptCompiler) {
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
lookup: 4,
|
793
|
-
append: 5,
|
794
|
-
invokeMustache: 6,
|
795
|
-
appendEscaped: 7,
|
796
|
-
pushString: 8,
|
797
|
-
truthyOrFallback: 9,
|
798
|
-
functionOrFallback: 10,
|
799
|
-
invokeProgram: 11,
|
800
|
-
invokePartial: 12,
|
801
|
-
push: 13,
|
802
|
-
assignToHash: 15,
|
803
|
-
pushStringParam: 16
|
804
|
-
};
|
805
|
-
|
806
|
-
Compiler.MULTI_PARAM_OPCODES = {
|
807
|
-
appendContent: 1,
|
808
|
-
getContext: 1,
|
809
|
-
lookupWithHelpers: 2,
|
810
|
-
lookup: 1,
|
811
|
-
invokeMustache: 3,
|
812
|
-
pushString: 1,
|
813
|
-
truthyOrFallback: 1,
|
814
|
-
functionOrFallback: 1,
|
815
|
-
invokeProgram: 3,
|
816
|
-
invokePartial: 1,
|
817
|
-
push: 1,
|
818
|
-
assignToHash: 1,
|
819
|
-
pushStringParam: 1
|
820
|
-
};
|
821
|
-
|
822
|
-
Compiler.DISASSEMBLE_MAP = {};
|
823
|
-
|
824
|
-
for(var prop in Compiler.OPCODE_MAP) {
|
825
|
-
var value = Compiler.OPCODE_MAP[prop];
|
826
|
-
Compiler.DISASSEMBLE_MAP[value] = prop;
|
827
|
-
}
|
828
|
-
|
829
|
-
Compiler.multiParamSize = function(code) {
|
830
|
-
return Compiler.MULTI_PARAM_OPCODES[Compiler.DISASSEMBLE_MAP[code]];
|
831
|
-
};
|
802
|
+
// the foundHelper register will disambiguate helper lookup from finding a
|
803
|
+
// function in a context. This is necessary for mustache compatibility, which
|
804
|
+
// requires that context functions in blocks are evaluated by blockHelperMissing,
|
805
|
+
// and then proceed as if the resulting value was provided to blockHelperMissing.
|
832
806
|
|
833
807
|
Compiler.prototype = {
|
834
808
|
compiler: Compiler,
|
835
809
|
|
836
810
|
disassemble: function() {
|
837
|
-
var opcodes = this.opcodes, opcode,
|
838
|
-
var out = [], str, name, value;
|
811
|
+
var opcodes = this.opcodes, opcode, out = [], params, param;
|
839
812
|
|
840
|
-
for(var i=0, l=opcodes.length; i<l; i++) {
|
813
|
+
for (var i=0, l=opcodes.length; i<l; i++) {
|
841
814
|
opcode = opcodes[i];
|
842
815
|
|
843
|
-
if(opcode === 'DECLARE') {
|
844
|
-
name =
|
845
|
-
value = opcodes[++i];
|
846
|
-
out.push("DECLARE " + name + " = " + value);
|
816
|
+
if (opcode.opcode === 'DECLARE') {
|
817
|
+
out.push("DECLARE " + opcode.name + "=" + opcode.value);
|
847
818
|
} else {
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
for(var j=0; j<extraParams; j++) {
|
854
|
-
nextCode = opcodes[++i];
|
855
|
-
|
856
|
-
if(typeof nextCode === "string") {
|
857
|
-
nextCode = "\"" + nextCode.replace("\n", "\\n") + "\"";
|
819
|
+
params = [];
|
820
|
+
for (var j=0; j<opcode.args.length; j++) {
|
821
|
+
param = opcode.args[j];
|
822
|
+
if (typeof param === "string") {
|
823
|
+
param = "\"" + param.replace("\n", "\\n") + "\"";
|
858
824
|
}
|
859
|
-
|
860
|
-
codes.push(nextCode);
|
825
|
+
params.push(param);
|
861
826
|
}
|
862
|
-
|
863
|
-
str = str + " " + codes.join(" ");
|
864
|
-
|
865
|
-
out.push(str);
|
827
|
+
out.push(opcode.opcode + " " + params.join(" "));
|
866
828
|
}
|
867
829
|
}
|
868
830
|
|
@@ -936,32 +898,42 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
936
898
|
},
|
937
899
|
|
938
900
|
block: function(block) {
|
939
|
-
var mustache = block.mustache
|
940
|
-
|
941
|
-
|
942
|
-
var params = this.setupStackForMustache(mustache);
|
901
|
+
var mustache = block.mustache,
|
902
|
+
program = block.program,
|
903
|
+
inverse = block.inverse;
|
943
904
|
|
944
|
-
|
945
|
-
|
946
|
-
if(block.program.inverse) {
|
947
|
-
inverseGuid = this.compileProgram(block.program.inverse);
|
948
|
-
this.declare('inverse', inverseGuid);
|
905
|
+
if (program) {
|
906
|
+
program = this.compileProgram(program);
|
949
907
|
}
|
950
908
|
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
},
|
909
|
+
if (inverse) {
|
910
|
+
inverse = this.compileProgram(inverse);
|
911
|
+
}
|
955
912
|
|
956
|
-
|
957
|
-
var params = this.setupStackForMustache(block.mustache);
|
913
|
+
var type = this.classifyMustache(mustache);
|
958
914
|
|
959
|
-
|
915
|
+
if (type === "helper") {
|
916
|
+
this.helperMustache(mustache, program, inverse);
|
917
|
+
} else if (type === "simple") {
|
918
|
+
this.simpleMustache(mustache);
|
960
919
|
|
961
|
-
|
920
|
+
// now that the simple mustache is resolved, we need to
|
921
|
+
// evaluate it by executing `blockHelperMissing`
|
922
|
+
this.opcode('pushProgram', program);
|
923
|
+
this.opcode('pushProgram', inverse);
|
924
|
+
this.opcode('pushLiteral', '{}');
|
925
|
+
this.opcode('blockValue');
|
926
|
+
} else {
|
927
|
+
this.ambiguousMustache(mustache, program, inverse);
|
928
|
+
|
929
|
+
// now that the simple mustache is resolved, we need to
|
930
|
+
// evaluate it by executing `blockHelperMissing`
|
931
|
+
this.opcode('pushProgram', program);
|
932
|
+
this.opcode('pushProgram', inverse);
|
933
|
+
this.opcode('pushLiteral', '{}');
|
934
|
+
this.opcode('ambiguousBlockValue');
|
935
|
+
}
|
962
936
|
|
963
|
-
this.opcode('invokeProgram', null, params.length, !!block.mustache.hash);
|
964
|
-
this.declare('inverse', null);
|
965
937
|
this.opcode('append');
|
966
938
|
},
|
967
939
|
|
@@ -998,44 +970,140 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
998
970
|
},
|
999
971
|
|
1000
972
|
mustache: function(mustache) {
|
1001
|
-
var
|
973
|
+
var options = this.options;
|
974
|
+
var type = this.classifyMustache(mustache);
|
1002
975
|
|
1003
|
-
|
976
|
+
if (type === "simple") {
|
977
|
+
this.simpleMustache(mustache);
|
978
|
+
} else if (type === "helper") {
|
979
|
+
this.helperMustache(mustache);
|
980
|
+
} else {
|
981
|
+
this.ambiguousMustache(mustache);
|
982
|
+
}
|
1004
983
|
|
1005
|
-
if(mustache.escaped && !
|
984
|
+
if(mustache.escaped && !options.noEscape) {
|
1006
985
|
this.opcode('appendEscaped');
|
1007
986
|
} else {
|
1008
987
|
this.opcode('append');
|
1009
988
|
}
|
1010
989
|
},
|
1011
990
|
|
991
|
+
ambiguousMustache: function(mustache, program, inverse) {
|
992
|
+
var id = mustache.id, name = id.parts[0];
|
993
|
+
|
994
|
+
this.opcode('getContext', id.depth);
|
995
|
+
|
996
|
+
this.opcode('pushProgram', program);
|
997
|
+
this.opcode('pushProgram', inverse);
|
998
|
+
|
999
|
+
this.opcode('invokeAmbiguous', name);
|
1000
|
+
},
|
1001
|
+
|
1002
|
+
simpleMustache: function(mustache, program, inverse) {
|
1003
|
+
var id = mustache.id;
|
1004
|
+
|
1005
|
+
if (id.type === 'DATA') {
|
1006
|
+
this.DATA(id);
|
1007
|
+
} else if (id.parts.length) {
|
1008
|
+
this.ID(id);
|
1009
|
+
} else {
|
1010
|
+
// Simplified ID for `this`
|
1011
|
+
this.addDepth(id.depth);
|
1012
|
+
this.opcode('getContext', id.depth);
|
1013
|
+
this.opcode('pushContext');
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
this.opcode('resolvePossibleLambda');
|
1017
|
+
},
|
1018
|
+
|
1019
|
+
helperMustache: function(mustache, program, inverse) {
|
1020
|
+
var params = this.setupFullMustacheParams(mustache, program, inverse),
|
1021
|
+
name = mustache.id.parts[0];
|
1022
|
+
|
1023
|
+
if (this.options.knownHelpers[name]) {
|
1024
|
+
this.opcode('invokeKnownHelper', params.length, name);
|
1025
|
+
} else if (this.knownHelpersOnly) {
|
1026
|
+
throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
|
1027
|
+
} else {
|
1028
|
+
this.opcode('invokeHelper', params.length, name);
|
1029
|
+
}
|
1030
|
+
},
|
1031
|
+
|
1012
1032
|
ID: function(id) {
|
1013
1033
|
this.addDepth(id.depth);
|
1014
|
-
|
1015
1034
|
this.opcode('getContext', id.depth);
|
1016
1035
|
|
1017
|
-
|
1036
|
+
var name = id.parts[0];
|
1037
|
+
if (!name) {
|
1038
|
+
this.opcode('pushContext');
|
1039
|
+
} else {
|
1040
|
+
this.opcode('lookupOnContext', id.parts[0]);
|
1041
|
+
}
|
1018
1042
|
|
1019
1043
|
for(var i=1, l=id.parts.length; i<l; i++) {
|
1020
1044
|
this.opcode('lookup', id.parts[i]);
|
1021
1045
|
}
|
1022
1046
|
},
|
1023
1047
|
|
1048
|
+
DATA: function(data) {
|
1049
|
+
this.options.data = true;
|
1050
|
+
this.opcode('lookupData', data.id);
|
1051
|
+
},
|
1052
|
+
|
1024
1053
|
STRING: function(string) {
|
1025
1054
|
this.opcode('pushString', string.string);
|
1026
1055
|
},
|
1027
1056
|
|
1028
1057
|
INTEGER: function(integer) {
|
1029
|
-
this.opcode('
|
1058
|
+
this.opcode('pushLiteral', integer.integer);
|
1030
1059
|
},
|
1031
1060
|
|
1032
1061
|
BOOLEAN: function(bool) {
|
1033
|
-
this.opcode('
|
1062
|
+
this.opcode('pushLiteral', bool.bool);
|
1034
1063
|
},
|
1035
1064
|
|
1036
1065
|
comment: function() {},
|
1037
1066
|
|
1038
1067
|
// HELPERS
|
1068
|
+
opcode: function(name) {
|
1069
|
+
this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
|
1070
|
+
},
|
1071
|
+
|
1072
|
+
declare: function(name, value) {
|
1073
|
+
this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
|
1074
|
+
},
|
1075
|
+
|
1076
|
+
addDepth: function(depth) {
|
1077
|
+
if(isNaN(depth)) { throw new Error("EWOT"); }
|
1078
|
+
if(depth === 0) { return; }
|
1079
|
+
|
1080
|
+
if(!this.depths[depth]) {
|
1081
|
+
this.depths[depth] = true;
|
1082
|
+
this.depths.list.push(depth);
|
1083
|
+
}
|
1084
|
+
},
|
1085
|
+
|
1086
|
+
classifyMustache: function(mustache) {
|
1087
|
+
var isHelper = mustache.isHelper;
|
1088
|
+
var isEligible = mustache.eligibleHelper;
|
1089
|
+
var options = this.options;
|
1090
|
+
|
1091
|
+
// if ambiguous, we can possibly resolve the ambiguity now
|
1092
|
+
if (isEligible && !isHelper) {
|
1093
|
+
var name = mustache.id.parts[0];
|
1094
|
+
|
1095
|
+
if (options.knownHelpers[name]) {
|
1096
|
+
isHelper = true;
|
1097
|
+
} else if (options.knownHelpersOnly) {
|
1098
|
+
isEligible = false;
|
1099
|
+
}
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
if (isHelper) { return "helper"; }
|
1103
|
+
else if (isEligible) { return "ambiguous"; }
|
1104
|
+
else { return "simple"; }
|
1105
|
+
},
|
1106
|
+
|
1039
1107
|
pushParams: function(params) {
|
1040
1108
|
var i = params.length, param;
|
1041
1109
|
|
@@ -1055,43 +1123,41 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1055
1123
|
}
|
1056
1124
|
},
|
1057
1125
|
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
if(val2 !== undefined) { this.opcodes.push(val2); }
|
1062
|
-
if(val3 !== undefined) { this.opcodes.push(val3); }
|
1063
|
-
},
|
1064
|
-
|
1065
|
-
declare: function(name, value) {
|
1066
|
-
this.opcodes.push('DECLARE');
|
1067
|
-
this.opcodes.push(name);
|
1068
|
-
this.opcodes.push(value);
|
1069
|
-
},
|
1070
|
-
|
1071
|
-
addDepth: function(depth) {
|
1072
|
-
if(depth === 0) { return; }
|
1126
|
+
setupMustacheParams: function(mustache) {
|
1127
|
+
var params = mustache.params;
|
1128
|
+
this.pushParams(params);
|
1073
1129
|
|
1074
|
-
if(
|
1075
|
-
this.
|
1076
|
-
|
1130
|
+
if(mustache.hash) {
|
1131
|
+
this.hash(mustache.hash);
|
1132
|
+
} else {
|
1133
|
+
this.opcode('pushLiteral', '{}');
|
1077
1134
|
}
|
1135
|
+
|
1136
|
+
return params;
|
1078
1137
|
},
|
1079
1138
|
|
1080
|
-
|
1139
|
+
// this will replace setupMustacheParams when we're done
|
1140
|
+
setupFullMustacheParams: function(mustache, program, inverse) {
|
1081
1141
|
var params = mustache.params;
|
1082
|
-
|
1083
1142
|
this.pushParams(params);
|
1084
1143
|
|
1144
|
+
this.opcode('pushProgram', program);
|
1145
|
+
this.opcode('pushProgram', inverse);
|
1146
|
+
|
1085
1147
|
if(mustache.hash) {
|
1086
1148
|
this.hash(mustache.hash);
|
1149
|
+
} else {
|
1150
|
+
this.opcode('pushLiteral', '{}');
|
1087
1151
|
}
|
1088
1152
|
|
1089
|
-
this.ID(mustache.id);
|
1090
|
-
|
1091
1153
|
return params;
|
1092
1154
|
}
|
1093
1155
|
};
|
1094
1156
|
|
1157
|
+
var Literal = function(value) {
|
1158
|
+
this.value = value;
|
1159
|
+
};
|
1160
|
+
|
1095
1161
|
JavaScriptCompiler.prototype = {
|
1096
1162
|
// PUBLIC API: You can override these methods in a subclass to provide
|
1097
1163
|
// alternative compiled forms for name lookup and buffering semantics
|
@@ -1125,18 +1191,21 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1125
1191
|
this.environment = environment;
|
1126
1192
|
this.options = options || {};
|
1127
1193
|
|
1194
|
+
Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
|
1195
|
+
|
1128
1196
|
this.name = this.environment.name;
|
1129
1197
|
this.isChild = !!context;
|
1130
1198
|
this.context = context || {
|
1131
1199
|
programs: [],
|
1132
|
-
aliases: {
|
1133
|
-
registers: {list: []}
|
1200
|
+
aliases: { }
|
1134
1201
|
};
|
1135
1202
|
|
1136
1203
|
this.preamble();
|
1137
1204
|
|
1138
1205
|
this.stackSlot = 0;
|
1139
1206
|
this.stackVars = [];
|
1207
|
+
this.registers = { list: [] };
|
1208
|
+
this.compileStack = [];
|
1140
1209
|
|
1141
1210
|
this.compileChildren(environment, options);
|
1142
1211
|
|
@@ -1145,59 +1214,35 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1145
1214
|
this.i = 0;
|
1146
1215
|
|
1147
1216
|
for(l=opcodes.length; this.i<l; this.i++) {
|
1148
|
-
opcode = this.
|
1217
|
+
opcode = opcodes[this.i];
|
1149
1218
|
|
1150
|
-
if(opcode
|
1151
|
-
this.
|
1152
|
-
this[opcode[1]] = opcode[2];
|
1219
|
+
if(opcode.opcode === 'DECLARE') {
|
1220
|
+
this[opcode.name] = opcode.value;
|
1153
1221
|
} else {
|
1154
|
-
this.
|
1155
|
-
this[opcode[0]].apply(this, opcode[1]);
|
1222
|
+
this[opcode.opcode].apply(this, opcode.args);
|
1156
1223
|
}
|
1157
1224
|
}
|
1158
1225
|
|
1159
1226
|
return this.createFunctionContext(asObject);
|
1160
1227
|
},
|
1161
1228
|
|
1162
|
-
nextOpcode: function(
|
1163
|
-
var opcodes = this.environment.opcodes, opcode = opcodes[this.i +
|
1164
|
-
|
1165
|
-
|
1166
|
-
if(opcode === 'DECLARE') {
|
1167
|
-
name = opcodes[this.i + 1];
|
1168
|
-
val = opcodes[this.i + 2];
|
1169
|
-
return ['DECLARE', name, val];
|
1170
|
-
} else {
|
1171
|
-
name = Compiler.DISASSEMBLE_MAP[opcode];
|
1172
|
-
|
1173
|
-
extraParams = Compiler.multiParamSize(opcode);
|
1174
|
-
codes = [];
|
1175
|
-
|
1176
|
-
for(var j=0; j<extraParams; j++) {
|
1177
|
-
codes.push(opcodes[this.i + j + 1 + n]);
|
1178
|
-
}
|
1179
|
-
|
1180
|
-
return [name, codes];
|
1181
|
-
}
|
1229
|
+
nextOpcode: function() {
|
1230
|
+
var opcodes = this.environment.opcodes, opcode = opcodes[this.i + 1];
|
1231
|
+
return opcodes[this.i + 1];
|
1182
1232
|
},
|
1183
1233
|
|
1184
1234
|
eat: function(opcode) {
|
1185
|
-
this.i = this.i +
|
1235
|
+
this.i = this.i + 1;
|
1186
1236
|
},
|
1187
1237
|
|
1188
1238
|
preamble: function() {
|
1189
1239
|
var out = [];
|
1190
1240
|
|
1191
|
-
// this register will disambiguate helper lookup from finding a function in
|
1192
|
-
// a context. This is necessary for mustache compatibility, which requires
|
1193
|
-
// that context functions in blocks are evaluated by blockHelperMissing, and
|
1194
|
-
// then proceed as if the resulting value was provided to blockHelperMissing.
|
1195
|
-
this.useRegister('foundHelper');
|
1196
|
-
|
1197
1241
|
if (!this.isChild) {
|
1198
1242
|
var namespace = this.namespace;
|
1199
1243
|
var copies = "helpers = helpers || " + namespace + ".helpers;";
|
1200
|
-
if(this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
|
1244
|
+
if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
|
1245
|
+
if (this.options.data) { copies = copies + " data = data || {};"; }
|
1201
1246
|
out.push(copies);
|
1202
1247
|
} else {
|
1203
1248
|
out.push('');
|
@@ -1216,10 +1261,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1216
1261
|
},
|
1217
1262
|
|
1218
1263
|
createFunctionContext: function(asObject) {
|
1219
|
-
var locals = this.stackVars;
|
1220
|
-
if (!this.isChild) {
|
1221
|
-
locals = locals.concat(this.context.registers.list);
|
1222
|
-
}
|
1264
|
+
var locals = this.stackVars.concat(this.registers.list);
|
1223
1265
|
|
1224
1266
|
if(locals.length > 0) {
|
1225
1267
|
this.source[1] = this.source[1] + ", " + locals.join(", ");
|
@@ -1263,10 +1305,64 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1263
1305
|
}
|
1264
1306
|
},
|
1265
1307
|
|
1308
|
+
// [blockValue]
|
1309
|
+
//
|
1310
|
+
// On stack, before: hash, inverse, program, value
|
1311
|
+
// On stack, after: return value of blockHelperMissing
|
1312
|
+
//
|
1313
|
+
// The purpose of this opcode is to take a block of the form
|
1314
|
+
// `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
|
1315
|
+
// replace it on the stack with the result of properly
|
1316
|
+
// invoking blockHelperMissing.
|
1317
|
+
blockValue: function() {
|
1318
|
+
this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
|
1319
|
+
|
1320
|
+
var params = ["depth0"];
|
1321
|
+
this.setupParams(0, params);
|
1322
|
+
|
1323
|
+
this.replaceStack(function(current) {
|
1324
|
+
params.splice(1, 0, current);
|
1325
|
+
return current + " = blockHelperMissing.call(" + params.join(", ") + ")";
|
1326
|
+
});
|
1327
|
+
},
|
1328
|
+
|
1329
|
+
// [ambiguousBlockValue]
|
1330
|
+
//
|
1331
|
+
// On stack, before: hash, inverse, program, value
|
1332
|
+
// Compiler value, before: lastHelper=value of last found helper, if any
|
1333
|
+
// On stack, after, if no lastHelper: same as [blockValue]
|
1334
|
+
// On stack, after, if lastHelper: value
|
1335
|
+
ambiguousBlockValue: function() {
|
1336
|
+
this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
|
1337
|
+
|
1338
|
+
var params = ["depth0"];
|
1339
|
+
this.setupParams(0, params);
|
1340
|
+
|
1341
|
+
var current = this.topStack();
|
1342
|
+
params.splice(1, 0, current);
|
1343
|
+
|
1344
|
+
this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
|
1345
|
+
},
|
1346
|
+
|
1347
|
+
// [appendContent]
|
1348
|
+
//
|
1349
|
+
// On stack, before: ...
|
1350
|
+
// On stack, after: ...
|
1351
|
+
//
|
1352
|
+
// Appends the string value of `content` to the current buffer
|
1266
1353
|
appendContent: function(content) {
|
1267
1354
|
this.source.push(this.appendToBuffer(this.quotedString(content)));
|
1268
1355
|
},
|
1269
1356
|
|
1357
|
+
// [append]
|
1358
|
+
//
|
1359
|
+
// On stack, before: value, ...
|
1360
|
+
// On stack, after: ...
|
1361
|
+
//
|
1362
|
+
// Coerces `value` to a String and appends it to the current buffer.
|
1363
|
+
//
|
1364
|
+
// If `value` is truthy, or 0, it is coerced into a string and appended
|
1365
|
+
// Otherwise, the empty string is appended
|
1270
1366
|
append: function() {
|
1271
1367
|
var local = this.popStack();
|
1272
1368
|
this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
|
@@ -1275,163 +1371,242 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1275
1371
|
}
|
1276
1372
|
},
|
1277
1373
|
|
1374
|
+
// [appendEscaped]
|
1375
|
+
//
|
1376
|
+
// On stack, before: value, ...
|
1377
|
+
// On stack, after: ...
|
1378
|
+
//
|
1379
|
+
// Escape `value` and append it to the buffer
|
1278
1380
|
appendEscaped: function() {
|
1279
|
-
var opcode = this.nextOpcode(
|
1381
|
+
var opcode = this.nextOpcode(), extra = "";
|
1280
1382
|
this.context.aliases.escapeExpression = 'this.escapeExpression';
|
1281
1383
|
|
1282
|
-
if(opcode
|
1283
|
-
extra = " + " + this.quotedString(opcode[
|
1384
|
+
if(opcode && opcode.opcode === 'appendContent') {
|
1385
|
+
extra = " + " + this.quotedString(opcode.args[0]);
|
1284
1386
|
this.eat(opcode);
|
1285
1387
|
}
|
1286
1388
|
|
1287
1389
|
this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra));
|
1288
1390
|
},
|
1289
1391
|
|
1392
|
+
// [getContext]
|
1393
|
+
//
|
1394
|
+
// On stack, before: ...
|
1395
|
+
// On stack, after: ...
|
1396
|
+
// Compiler value, after: lastContext=depth
|
1397
|
+
//
|
1398
|
+
// Set the value of the `lastContext` compiler value to the depth
|
1290
1399
|
getContext: function(depth) {
|
1291
1400
|
if(this.lastContext !== depth) {
|
1292
1401
|
this.lastContext = depth;
|
1293
1402
|
}
|
1294
1403
|
},
|
1295
1404
|
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1405
|
+
// [lookupOnContext]
|
1406
|
+
//
|
1407
|
+
// On stack, before: ...
|
1408
|
+
// On stack, after: currentContext[name], ...
|
1409
|
+
//
|
1410
|
+
// Looks up the value of `name` on the current context and pushes
|
1411
|
+
// it onto the stack.
|
1412
|
+
lookupOnContext: function(name) {
|
1413
|
+
this.pushStack(this.nameLookup('depth' + this.lastContext, name, 'context'));
|
1414
|
+
},
|
1415
|
+
|
1416
|
+
// [pushContext]
|
1417
|
+
//
|
1418
|
+
// On stack, before: ...
|
1419
|
+
// On stack, after: currentContext, ...
|
1420
|
+
//
|
1421
|
+
// Pushes the value of the current context onto the stack.
|
1422
|
+
pushContext: function() {
|
1423
|
+
this.pushStackLiteral('depth' + this.lastContext);
|
1424
|
+
},
|
1425
|
+
|
1426
|
+
// [resolvePossibleLambda]
|
1427
|
+
//
|
1428
|
+
// On stack, before: value, ...
|
1429
|
+
// On stack, after: resolved value, ...
|
1430
|
+
//
|
1431
|
+
// If the `value` is a lambda, replace it on the stack by
|
1432
|
+
// the return value of the lambda
|
1433
|
+
resolvePossibleLambda: function() {
|
1434
|
+
this.context.aliases.functionType = '"function"';
|
1435
|
+
|
1436
|
+
this.replaceStack(function(current) {
|
1437
|
+
return "typeof " + current + " === functionType ? " + current + "() : " + current;
|
1438
|
+
});
|
1318
1439
|
},
|
1319
1440
|
|
1441
|
+
// [lookup]
|
1442
|
+
//
|
1443
|
+
// On stack, before: value, ...
|
1444
|
+
// On stack, after: value[name], ...
|
1445
|
+
//
|
1446
|
+
// Replace the value on the stack with the result of looking
|
1447
|
+
// up `name` on `value`
|
1320
1448
|
lookup: function(name) {
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1449
|
+
this.replaceStack(function(current) {
|
1450
|
+
return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
|
1451
|
+
});
|
1324
1452
|
},
|
1325
1453
|
|
1454
|
+
// [lookupData]
|
1455
|
+
//
|
1456
|
+
// On stack, before: ...
|
1457
|
+
// On stack, after: data[id], ...
|
1458
|
+
//
|
1459
|
+
// Push the result of looking up `id` on the current data
|
1460
|
+
lookupData: function(id) {
|
1461
|
+
this.pushStack(this.nameLookup('data', id, 'data'));
|
1462
|
+
},
|
1463
|
+
|
1464
|
+
// [pushStringParam]
|
1465
|
+
//
|
1466
|
+
// On stack, before: ...
|
1467
|
+
// On stack, after: string, currentContext, ...
|
1468
|
+
//
|
1469
|
+
// This opcode is designed for use in string mode, which
|
1470
|
+
// provides the string value of a parameter along with its
|
1471
|
+
// depth rather than resolving it immediately.
|
1326
1472
|
pushStringParam: function(string) {
|
1327
|
-
this.
|
1473
|
+
this.pushStackLiteral('depth' + this.lastContext);
|
1328
1474
|
this.pushString(string);
|
1329
1475
|
},
|
1330
1476
|
|
1477
|
+
// [pushString]
|
1478
|
+
//
|
1479
|
+
// On stack, before: ...
|
1480
|
+
// On stack, after: quotedString(string), ...
|
1481
|
+
//
|
1482
|
+
// Push a quoted version of `string` onto the stack
|
1331
1483
|
pushString: function(string) {
|
1332
|
-
this.
|
1333
|
-
},
|
1334
|
-
|
1335
|
-
push
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
if (needsRegister) {
|
1370
|
-
this.register('tmp1', program);
|
1371
|
-
stringOptions = 'tmp1';
|
1484
|
+
this.pushStackLiteral(this.quotedString(string));
|
1485
|
+
},
|
1486
|
+
|
1487
|
+
// [push]
|
1488
|
+
//
|
1489
|
+
// On stack, before: ...
|
1490
|
+
// On stack, after: expr, ...
|
1491
|
+
//
|
1492
|
+
// Push an expression onto the stack
|
1493
|
+
push: function(expr) {
|
1494
|
+
this.pushStack(expr);
|
1495
|
+
},
|
1496
|
+
|
1497
|
+
// [pushLiteral]
|
1498
|
+
//
|
1499
|
+
// On stack, before: ...
|
1500
|
+
// On stack, after: value, ...
|
1501
|
+
//
|
1502
|
+
// Pushes a value onto the stack. This operation prevents
|
1503
|
+
// the compiler from creating a temporary variable to hold
|
1504
|
+
// it.
|
1505
|
+
pushLiteral: function(value) {
|
1506
|
+
this.pushStackLiteral(value);
|
1507
|
+
},
|
1508
|
+
|
1509
|
+
// [pushProgram]
|
1510
|
+
//
|
1511
|
+
// On stack, before: ...
|
1512
|
+
// On stack, after: program(guid), ...
|
1513
|
+
//
|
1514
|
+
// Push a program expression onto the stack. This takes
|
1515
|
+
// a compile-time guid and converts it into a runtime-accessible
|
1516
|
+
// expression.
|
1517
|
+
pushProgram: function(guid) {
|
1518
|
+
if (guid != null) {
|
1519
|
+
this.pushStackLiteral(this.programExpression(guid));
|
1372
1520
|
} else {
|
1373
|
-
|
1374
|
-
}
|
1375
|
-
|
1376
|
-
if (needsRegister) {
|
1377
|
-
var hash = (hasHash ? this.popStack() : '{}');
|
1378
|
-
this.source.push('tmp1.hash = ' + hash + ';');
|
1379
|
-
}
|
1380
|
-
|
1381
|
-
if(this.options.stringParams) {
|
1382
|
-
this.source.push('tmp1.contexts = [];');
|
1383
|
-
}
|
1384
|
-
|
1385
|
-
for(var i=0; i<paramSize; i++) {
|
1386
|
-
param = this.popStack();
|
1387
|
-
params.push(param);
|
1388
|
-
|
1389
|
-
if(this.options.stringParams) {
|
1390
|
-
this.source.push('tmp1.contexts.push(' + this.popStack() + ');');
|
1391
|
-
}
|
1521
|
+
this.pushStackLiteral(null);
|
1392
1522
|
}
|
1393
|
-
|
1394
|
-
if(inverse) {
|
1395
|
-
this.source.push('tmp1.fn = tmp1;');
|
1396
|
-
this.source.push('tmp1.inverse = ' + inverse + ';');
|
1397
|
-
}
|
1398
|
-
|
1399
|
-
if(this.options.data) {
|
1400
|
-
this.source.push('tmp1.data = data;');
|
1401
|
-
}
|
1402
|
-
|
1403
|
-
params.push(stringOptions);
|
1404
|
-
|
1405
|
-
this.populateCall(params, id, helperId || id, fn, program !== '{}');
|
1406
1523
|
},
|
1407
1524
|
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1525
|
+
// [invokeHelper]
|
1526
|
+
//
|
1527
|
+
// On stack, before: hash, inverse, program, params..., ...
|
1528
|
+
// On stack, after: result of helper invocation
|
1529
|
+
//
|
1530
|
+
// Pops off the helper's parameters, invokes the helper,
|
1531
|
+
// and pushes the helper's return value onto the stack.
|
1532
|
+
//
|
1533
|
+
// If the helper is not found, `helperMissing` is called.
|
1534
|
+
invokeHelper: function(paramSize, name) {
|
1535
|
+
this.context.aliases.helperMissing = 'helpers.helperMissing';
|
1536
|
+
|
1537
|
+
var helper = this.lastHelper = this.setupHelper(paramSize, name);
|
1538
|
+
this.register('foundHelper', helper.name);
|
1539
|
+
|
1540
|
+
this.pushStack("foundHelper ? foundHelper.call(" +
|
1541
|
+
helper.callParams + ") " + ": helperMissing.call(" +
|
1542
|
+
helper.helperMissingParams + ")");
|
1543
|
+
},
|
1544
|
+
|
1545
|
+
// [invokeKnownHelper]
|
1546
|
+
//
|
1547
|
+
// On stack, before: hash, inverse, program, params..., ...
|
1548
|
+
// On stack, after: result of helper invocation
|
1549
|
+
//
|
1550
|
+
// This operation is used when the helper is known to exist,
|
1551
|
+
// so a `helperMissing` fallback is not required.
|
1552
|
+
invokeKnownHelper: function(paramSize, name) {
|
1553
|
+
var helper = this.setupHelper(paramSize, name);
|
1554
|
+
this.pushStack(helper.name + ".call(" + helper.callParams + ")");
|
1555
|
+
},
|
1556
|
+
|
1557
|
+
// [invokeAmbiguous]
|
1558
|
+
//
|
1559
|
+
// On stack, before: hash, inverse, program, params..., ...
|
1560
|
+
// On stack, after: result of disambiguation
|
1561
|
+
//
|
1562
|
+
// This operation is used when an expression like `{{foo}}`
|
1563
|
+
// is provided, but we don't know at compile-time whether it
|
1564
|
+
// is a helper or a path.
|
1565
|
+
//
|
1566
|
+
// This operation emits more code than the other options,
|
1567
|
+
// and can be avoided by passing the `knownHelpers` and
|
1568
|
+
// `knownHelpersOnly` flags at compile-time.
|
1569
|
+
invokeAmbiguous: function(name) {
|
1570
|
+
this.context.aliases.functionType = '"function"';
|
1571
|
+
|
1572
|
+
this.pushStackLiteral('{}');
|
1573
|
+
var helper = this.setupHelper(0, name);
|
1574
|
+
|
1575
|
+
var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
|
1576
|
+
this.register('foundHelper', helperName);
|
1577
|
+
|
1578
|
+
var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
|
1412
1579
|
var nextStack = this.nextStack();
|
1413
1580
|
|
1414
|
-
if (
|
1415
|
-
|
1416
|
-
} else {
|
1417
|
-
this.context.aliases.functionType = '"function"';
|
1418
|
-
var condition = program ? "foundHelper && " : "";
|
1419
|
-
this.source.push("if(" + condition + "typeof " + id + " === functionType) { " + nextStack + " = " + id + ".call(" + paramString + "); }");
|
1420
|
-
}
|
1421
|
-
fn.call(this, nextStack, helperMissingString, id);
|
1422
|
-
this.usingKnownHelper = false;
|
1581
|
+
this.source.push('if (foundHelper) { ' + nextStack + ' = foundHelper.call(' + helper.callParams + '); }');
|
1582
|
+
this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '() : ' + nextStack + '; }');
|
1423
1583
|
},
|
1424
1584
|
|
1425
|
-
invokePartial
|
1426
|
-
|
1585
|
+
// [invokePartial]
|
1586
|
+
//
|
1587
|
+
// On stack, before: context, ...
|
1588
|
+
// On stack after: result of partial invocation
|
1589
|
+
//
|
1590
|
+
// This operation pops off a context, invokes a partial with that context,
|
1591
|
+
// and pushes the result of the invocation back.
|
1592
|
+
invokePartial: function(name) {
|
1593
|
+
var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
|
1427
1594
|
|
1428
1595
|
if (this.options.data) {
|
1429
1596
|
params.push("data");
|
1430
1597
|
}
|
1431
1598
|
|
1599
|
+
this.context.aliases.self = "this";
|
1432
1600
|
this.pushStack("self.invokePartial(" + params.join(", ") + ");");
|
1433
1601
|
},
|
1434
1602
|
|
1603
|
+
// [assignToHash]
|
1604
|
+
//
|
1605
|
+
// On stack, before: value, hash, ...
|
1606
|
+
// On stack, after: hash, ...
|
1607
|
+
//
|
1608
|
+
// Pops a value and hash off the stack, assigns `hash[key] = value`
|
1609
|
+
// and pushes the hash back onto the stack.
|
1435
1610
|
assignToHash: function(key) {
|
1436
1611
|
var value = this.popStack();
|
1437
1612
|
var hash = this.topStack();
|
@@ -1459,7 +1634,11 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1459
1634
|
},
|
1460
1635
|
|
1461
1636
|
programExpression: function(guid) {
|
1462
|
-
|
1637
|
+
this.context.aliases.self = "this";
|
1638
|
+
|
1639
|
+
if(guid == null) {
|
1640
|
+
return "self.noop";
|
1641
|
+
}
|
1463
1642
|
|
1464
1643
|
var child = this.environment.children[guid],
|
1465
1644
|
depths = child.depths.list, depth;
|
@@ -1487,29 +1666,61 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1487
1666
|
},
|
1488
1667
|
|
1489
1668
|
useRegister: function(name) {
|
1490
|
-
if(!this.
|
1491
|
-
this.
|
1492
|
-
this.
|
1669
|
+
if(!this.registers[name]) {
|
1670
|
+
this.registers[name] = true;
|
1671
|
+
this.registers.list.push(name);
|
1493
1672
|
}
|
1494
1673
|
},
|
1495
1674
|
|
1675
|
+
pushStackLiteral: function(item) {
|
1676
|
+
this.compileStack.push(new Literal(item));
|
1677
|
+
return item;
|
1678
|
+
},
|
1679
|
+
|
1496
1680
|
pushStack: function(item) {
|
1497
|
-
this.source.push(this.
|
1681
|
+
this.source.push(this.incrStack() + " = " + item + ";");
|
1682
|
+
this.compileStack.push("stack" + this.stackSlot);
|
1683
|
+
return "stack" + this.stackSlot;
|
1684
|
+
},
|
1685
|
+
|
1686
|
+
replaceStack: function(callback) {
|
1687
|
+
var item = callback.call(this, this.topStack());
|
1688
|
+
|
1689
|
+
this.source.push(this.topStack() + " = " + item + ";");
|
1498
1690
|
return "stack" + this.stackSlot;
|
1499
1691
|
},
|
1500
1692
|
|
1501
|
-
nextStack: function() {
|
1693
|
+
nextStack: function(skipCompileStack) {
|
1694
|
+
var name = this.incrStack();
|
1695
|
+
this.compileStack.push("stack" + this.stackSlot);
|
1696
|
+
return name;
|
1697
|
+
},
|
1698
|
+
|
1699
|
+
incrStack: function() {
|
1502
1700
|
this.stackSlot++;
|
1503
1701
|
if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
|
1504
1702
|
return "stack" + this.stackSlot;
|
1505
1703
|
},
|
1506
1704
|
|
1507
1705
|
popStack: function() {
|
1508
|
-
|
1706
|
+
var item = this.compileStack.pop();
|
1707
|
+
|
1708
|
+
if (item instanceof Literal) {
|
1709
|
+
return item.value;
|
1710
|
+
} else {
|
1711
|
+
this.stackSlot--;
|
1712
|
+
return item;
|
1713
|
+
}
|
1509
1714
|
},
|
1510
1715
|
|
1511
1716
|
topStack: function() {
|
1512
|
-
|
1717
|
+
var item = this.compileStack[this.compileStack.length - 1];
|
1718
|
+
|
1719
|
+
if (item instanceof Literal) {
|
1720
|
+
return item.value;
|
1721
|
+
} else {
|
1722
|
+
return item;
|
1723
|
+
}
|
1513
1724
|
},
|
1514
1725
|
|
1515
1726
|
quotedString: function(str) {
|
@@ -1518,6 +1729,67 @@ Handlebars.JavaScriptCompiler = function() {};
|
|
1518
1729
|
.replace(/"/g, '\\"')
|
1519
1730
|
.replace(/\n/g, '\\n')
|
1520
1731
|
.replace(/\r/g, '\\r') + '"';
|
1732
|
+
},
|
1733
|
+
|
1734
|
+
setupHelper: function(paramSize, name) {
|
1735
|
+
var params = [];
|
1736
|
+
this.setupParams(paramSize, params);
|
1737
|
+
var foundHelper = this.nameLookup('helpers', name, 'helper');
|
1738
|
+
|
1739
|
+
return {
|
1740
|
+
params: params,
|
1741
|
+
name: foundHelper,
|
1742
|
+
callParams: ["depth0"].concat(params).join(", "),
|
1743
|
+
helperMissingParams: ["depth0", this.quotedString(name)].concat(params).join(", ")
|
1744
|
+
};
|
1745
|
+
},
|
1746
|
+
|
1747
|
+
// the params and contexts arguments are passed in arrays
|
1748
|
+
// to fill in
|
1749
|
+
setupParams: function(paramSize, params) {
|
1750
|
+
var options = [], contexts = [], param, inverse, program;
|
1751
|
+
|
1752
|
+
options.push("hash:" + this.popStack());
|
1753
|
+
|
1754
|
+
inverse = this.popStack();
|
1755
|
+
program = this.popStack();
|
1756
|
+
|
1757
|
+
// Avoid setting fn and inverse if neither are set. This allows
|
1758
|
+
// helpers to do a check for `if (options.fn)`
|
1759
|
+
if (program || inverse) {
|
1760
|
+
if (!program) {
|
1761
|
+
this.context.aliases.self = "this";
|
1762
|
+
program = "self.noop";
|
1763
|
+
}
|
1764
|
+
|
1765
|
+
if (!inverse) {
|
1766
|
+
this.context.aliases.self = "this";
|
1767
|
+
inverse = "self.noop";
|
1768
|
+
}
|
1769
|
+
|
1770
|
+
options.push("inverse:" + inverse);
|
1771
|
+
options.push("fn:" + program);
|
1772
|
+
}
|
1773
|
+
|
1774
|
+
for(var i=0; i<paramSize; i++) {
|
1775
|
+
param = this.popStack();
|
1776
|
+
params.push(param);
|
1777
|
+
|
1778
|
+
if(this.options.stringParams) {
|
1779
|
+
contexts.push(this.popStack());
|
1780
|
+
}
|
1781
|
+
}
|
1782
|
+
|
1783
|
+
if (this.options.stringParams) {
|
1784
|
+
options.push("contexts:[" + contexts.join(",") + "]");
|
1785
|
+
}
|
1786
|
+
|
1787
|
+
if(this.options.data) {
|
1788
|
+
options.push("data:data");
|
1789
|
+
}
|
1790
|
+
|
1791
|
+
params.push("{" + options.join(",") + "}");
|
1792
|
+
return params.join(", ");
|
1521
1793
|
}
|
1522
1794
|
};
|
1523
1795
|
|
@@ -1638,7 +1910,7 @@ Handlebars.VM = {
|
|
1638
1910
|
} else if (!Handlebars.compile) {
|
1639
1911
|
throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
|
1640
1912
|
} else {
|
1641
|
-
partials[name] = Handlebars.compile(partial);
|
1913
|
+
partials[name] = Handlebars.compile(partial, {data: data !== undefined});
|
1642
1914
|
return partials[name](context, options);
|
1643
1915
|
}
|
1644
1916
|
}
|