handlebars-source 1.0.0.rc4 → 1.0.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.

Potentially problematic release.


This version of handlebars-source might be problematic. Click here for more details.

Files changed (3) hide show
  1. data/dist/handlebars.js +1122 -1441
  2. data/dist/handlebars.runtime.js +87 -191
  3. metadata +5 -5
@@ -1,66 +1,22 @@
1
- /*
2
-
3
- Copyright (C) 2011 by Yehuda Katz
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
22
-
23
- */
24
-
25
- // lib/handlebars/browser-prefix.js
26
- var Handlebars = {};
27
-
28
- (function(Handlebars, undefined) {
29
- ;
30
1
  // lib/handlebars/base.js
31
2
 
32
- Handlebars.VERSION = "1.0.0-rc.4";
33
- Handlebars.COMPILER_REVISION = 3;
3
+ /*jshint eqnull:true*/
4
+ this.Handlebars = {};
34
5
 
35
- Handlebars.REVISION_CHANGES = {
36
- 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
37
- 2: '== 1.0.0-rc.3',
38
- 3: '>= 1.0.0-rc.4'
39
- };
6
+ (function(Handlebars) {
7
+
8
+ Handlebars.VERSION = "1.0.rc.1";
40
9
 
41
10
  Handlebars.helpers = {};
42
11
  Handlebars.partials = {};
43
12
 
44
- var toString = Object.prototype.toString,
45
- functionType = '[object Function]',
46
- objectType = '[object Object]';
47
-
48
13
  Handlebars.registerHelper = function(name, fn, inverse) {
49
- if (toString.call(name) === objectType) {
50
- if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); }
51
- Handlebars.Utils.extend(this.helpers, name);
52
- } else {
53
- if (inverse) { fn.not = inverse; }
54
- this.helpers[name] = fn;
55
- }
14
+ if(inverse) { fn.not = inverse; }
15
+ this.helpers[name] = fn;
56
16
  };
57
17
 
58
18
  Handlebars.registerPartial = function(name, str) {
59
- if (toString.call(name) === objectType) {
60
- Handlebars.Utils.extend(this.partials, name);
61
- } else {
62
- this.partials[name] = str;
63
- }
19
+ this.partials[name] = str;
64
20
  };
65
21
 
66
22
  Handlebars.registerHelper('helperMissing', function(arg) {
@@ -71,9 +27,13 @@ Handlebars.registerHelper('helperMissing', function(arg) {
71
27
  }
72
28
  });
73
29
 
30
+ var toString = Object.prototype.toString, functionType = "[object Function]";
31
+
74
32
  Handlebars.registerHelper('blockHelperMissing', function(context, options) {
75
33
  var inverse = options.inverse || function() {}, fn = options.fn;
76
34
 
35
+
36
+ var ret = "";
77
37
  var type = toString.call(context);
78
38
 
79
39
  if(type === functionType) { context = context.call(this); }
@@ -102,53 +62,22 @@ Handlebars.createFrame = Object.create || function(object) {
102
62
  return obj;
103
63
  };
104
64
 
105
- Handlebars.logger = {
106
- DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
107
-
108
- methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'},
109
-
110
- // can be overridden in the host environment
111
- log: function(level, obj) {
112
- if (Handlebars.logger.level <= level) {
113
- var method = Handlebars.logger.methodMap[level];
114
- if (typeof console !== 'undefined' && console[method]) {
115
- console[method].call(console, obj);
116
- }
117
- }
118
- }
119
- };
120
-
121
- Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); };
122
-
123
65
  Handlebars.registerHelper('each', function(context, options) {
124
66
  var fn = options.fn, inverse = options.inverse;
125
- var i = 0, ret = "", data;
67
+ var ret = "", data;
126
68
 
127
69
  if (options.data) {
128
70
  data = Handlebars.createFrame(options.data);
129
71
  }
130
72
 
131
- if(context && typeof context === 'object') {
132
- if(context instanceof Array){
133
- for(var j = context.length; i<j; i++) {
134
- if (data) { data.index = i; }
135
- ret = ret + fn(context[i], { data: data });
136
- }
137
- } else {
138
- for(var key in context) {
139
- if(context.hasOwnProperty(key)) {
140
- if(data) { data.key = key; }
141
- ret = ret + fn(context[key], {data: data});
142
- i++;
143
- }
144
- }
73
+ if(context && context.length > 0) {
74
+ for(var i=0, j=context.length; i<j; i++) {
75
+ if (data) { data.index = i; }
76
+ ret = ret + fn(context[i], { data: data });
145
77
  }
146
- }
147
-
148
- if(i === 0){
78
+ } else {
149
79
  ret = inverse(this);
150
80
  }
151
-
152
81
  return ret;
153
82
  });
154
83
 
@@ -164,128 +93,125 @@ Handlebars.registerHelper('if', function(context, options) {
164
93
  });
165
94
 
166
95
  Handlebars.registerHelper('unless', function(context, options) {
167
- return Handlebars.helpers['if'].call(this, context, {fn: options.inverse, inverse: options.fn});
96
+ var fn = options.fn, inverse = options.inverse;
97
+ options.fn = inverse;
98
+ options.inverse = fn;
99
+
100
+ return Handlebars.helpers['if'].call(this, context, options);
168
101
  });
169
102
 
170
103
  Handlebars.registerHelper('with', function(context, options) {
171
- if (!Handlebars.Utils.isEmpty(context)) return options.fn(context);
104
+ return options.fn(context);
172
105
  });
173
106
 
174
- Handlebars.registerHelper('log', function(context, options) {
175
- var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
176
- Handlebars.log(level, context);
107
+ Handlebars.registerHelper('log', function(context) {
108
+ Handlebars.log(context);
177
109
  });
110
+
111
+ }(this.Handlebars));
178
112
  ;
179
113
  // lib/handlebars/compiler/parser.js
180
114
  /* Jison generated parser */
181
115
  var handlebars = (function(){
182
116
  var parser = {trace: function trace() { },
183
117
  yy: {},
184
- symbols_: {"error":2,"root":3,"program":4,"EOF":5,"simpleInverse":6,"statements":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,"partialName":25,"params":26,"hash":27,"DATA":28,"param":29,"STRING":30,"INTEGER":31,"BOOLEAN":32,"hashSegments":33,"hashSegment":34,"ID":35,"EQUALS":36,"PARTIAL_NAME":37,"pathSegments":38,"SEP":39,"$accept":0,"$end":1},
185
- 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",28:"DATA",30:"STRING",31:"INTEGER",32:"BOOLEAN",35:"ID",36:"EQUALS",37:"PARTIAL_NAME",39:"SEP"},
186
- productions_: [0,[3,2],[4,2],[4,3],[4,2],[4,1],[4,1],[4,0],[7,1],[7,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],[6,2],[17,3],[17,2],[17,2],[17,1],[17,1],[26,2],[26,1],[29,1],[29,1],[29,1],[29,1],[29,1],[27,1],[33,2],[33,1],[34,3],[34,3],[34,3],[34,3],[34,3],[25,1],[21,1],[38,3],[38,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]],
187
121
  performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
188
122
 
189
123
  var $0 = $$.length - 1;
190
124
  switch (yystate) {
191
125
  case 1: return $$[$0-1];
192
126
  break;
193
- case 2: this.$ = new yy.ProgramNode([], $$[$0]);
127
+ case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]);
194
128
  break;
195
- case 3: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]);
129
+ case 3: this.$ = new yy.ProgramNode($$[$0]);
196
130
  break;
197
- case 4: this.$ = new yy.ProgramNode($$[$0-1], []);
131
+ case 4: this.$ = new yy.ProgramNode([]);
198
132
  break;
199
- case 5: this.$ = new yy.ProgramNode($$[$0]);
133
+ case 5: this.$ = [$$[$0]];
200
134
  break;
201
- case 6: this.$ = new yy.ProgramNode([], []);
135
+ case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
202
136
  break;
203
- case 7: this.$ = new yy.ProgramNode([]);
137
+ case 7: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]);
204
138
  break;
205
- case 8: this.$ = [$$[$0]];
139
+ case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]);
206
140
  break;
207
- case 9: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
141
+ case 9: this.$ = $$[$0];
208
142
  break;
209
- case 10: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]);
143
+ case 10: this.$ = $$[$0];
210
144
  break;
211
- case 11: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]);
145
+ case 11: this.$ = new yy.ContentNode($$[$0]);
212
146
  break;
213
- case 12: this.$ = $$[$0];
147
+ case 12: this.$ = new yy.CommentNode($$[$0]);
214
148
  break;
215
- case 13: this.$ = $$[$0];
149
+ case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
216
150
  break;
217
- case 14: this.$ = new yy.ContentNode($$[$0]);
151
+ case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
218
152
  break;
219
- case 15: this.$ = new yy.CommentNode($$[$0]);
153
+ case 15: this.$ = $$[$0-1];
220
154
  break;
221
155
  case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
222
156
  break;
223
- case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
224
- break;
225
- case 18: this.$ = $$[$0-1];
157
+ case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true);
226
158
  break;
227
- case 19: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
159
+ case 18: this.$ = new yy.PartialNode($$[$0-1]);
228
160
  break;
229
- case 20: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true);
161
+ case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]);
230
162
  break;
231
- case 21: this.$ = new yy.PartialNode($$[$0-1]);
163
+ case 20:
232
164
  break;
233
- case 22: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]);
165
+ case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]];
234
166
  break;
235
- case 23:
167
+ case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null];
236
168
  break;
237
- case 24: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]];
169
+ case 23: this.$ = [[$$[$0-1]], $$[$0]];
238
170
  break;
239
- case 25: this.$ = [[$$[$0-1]].concat($$[$0]), null];
171
+ case 24: this.$ = [[$$[$0]], null];
240
172
  break;
241
- case 26: this.$ = [[$$[$0-1]], $$[$0]];
173
+ case 25: this.$ = [[new yy.DataNode($$[$0])], null];
242
174
  break;
243
- case 27: this.$ = [[$$[$0]], null];
175
+ case 26: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
244
176
  break;
245
- case 28: this.$ = [[new yy.DataNode($$[$0])], null];
177
+ case 27: this.$ = [$$[$0]];
246
178
  break;
247
- case 29: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
179
+ case 28: this.$ = $$[$0];
248
180
  break;
249
- case 30: this.$ = [$$[$0]];
181
+ case 29: this.$ = new yy.StringNode($$[$0]);
250
182
  break;
251
- case 31: this.$ = $$[$0];
183
+ case 30: this.$ = new yy.IntegerNode($$[$0]);
252
184
  break;
253
- case 32: this.$ = new yy.StringNode($$[$0]);
185
+ case 31: this.$ = new yy.BooleanNode($$[$0]);
254
186
  break;
255
- case 33: this.$ = new yy.IntegerNode($$[$0]);
187
+ case 32: this.$ = new yy.DataNode($$[$0]);
256
188
  break;
257
- case 34: this.$ = new yy.BooleanNode($$[$0]);
189
+ case 33: this.$ = new yy.HashNode($$[$0]);
258
190
  break;
259
- case 35: this.$ = new yy.DataNode($$[$0]);
191
+ case 34: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
260
192
  break;
261
- case 36: this.$ = new yy.HashNode($$[$0]);
193
+ case 35: this.$ = [$$[$0]];
262
194
  break;
263
- case 37: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
195
+ case 36: this.$ = [$$[$0-2], $$[$0]];
264
196
  break;
265
- case 38: this.$ = [$$[$0]];
197
+ case 37: this.$ = [$$[$0-2], new yy.StringNode($$[$0])];
266
198
  break;
267
- case 39: this.$ = [$$[$0-2], $$[$0]];
199
+ case 38: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])];
268
200
  break;
269
- case 40: this.$ = [$$[$0-2], new yy.StringNode($$[$0])];
201
+ case 39: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])];
270
202
  break;
271
- case 41: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])];
203
+ case 40: this.$ = [$$[$0-2], new yy.DataNode($$[$0])];
272
204
  break;
273
- case 42: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])];
205
+ case 41: this.$ = new yy.IdNode($$[$0]);
274
206
  break;
275
- case 43: this.$ = [$$[$0-2], new yy.DataNode($$[$0])];
207
+ case 42: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
276
208
  break;
277
- case 44: this.$ = new yy.PartialNameNode($$[$0]);
278
- break;
279
- case 45: this.$ = new yy.IdNode($$[$0]);
280
- break;
281
- case 46: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
282
- break;
283
- case 47: this.$ = [$$[$0]];
209
+ case 43: this.$ = [$$[$0]];
284
210
  break;
285
211
  }
286
212
  },
287
- table: [{3:1,4:2,5:[2,7],6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],22:[1,14],23:[1,15],24:[1,16]},{1:[3]},{5:[1,17]},{5:[2,6],7:18,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,6],22:[1,14],23:[1,15],24:[1,16]},{5:[2,5],6:20,8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,5],22:[1,14],23:[1,15],24:[1,16]},{17:23,18:[1,22],21:24,28:[1,25],35:[1,27],38:26},{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]},{4:28,6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,7],22:[1,14],23:[1,15],24:[1,16]},{4:29,6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,7],22:[1,14],23:[1,15],24:[1,16]},{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]},{5:[2,13],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,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{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]},{17:30,21:24,28:[1,25],35:[1,27],38:26},{17:31,21:24,28:[1,25],35:[1,27],38:26},{17:32,21:24,28:[1,25],35:[1,27],38:26},{25:33,37:[1,34]},{1:[2,1]},{5:[2,2],8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,2],22:[1,14],23:[1,15],24:[1,16]},{17:23,21:24,28:[1,25],35:[1,27],38:26},{5:[2,4],7:35,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,4],22:[1,14],23:[1,15],24:[1,16]},{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,23],14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],24:[2,23]},{18:[1,36]},{18:[2,27],21:41,26:37,27:38,28:[1,45],29:39,30:[1,42],31:[1,43],32:[1,44],33:40,34:46,35:[1,47],38:26},{18:[2,28]},{18:[2,45],28:[2,45],30:[2,45],31:[2,45],32:[2,45],35:[2,45],39:[1,48]},{18:[2,47],28:[2,47],30:[2,47],31:[2,47],32:[2,47],35:[2,47],39:[2,47]},{10:49,20:[1,50]},{10:51,20:[1,50]},{18:[1,52]},{18:[1,53]},{18:[1,54]},{18:[1,55],21:56,35:[1,27],38:26},{18:[2,44],35:[2,44]},{5:[2,3],8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,3],22:[1,14],23:[1,15],24:[1,16]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{18:[2,25],21:41,27:57,28:[1,45],29:58,30:[1,42],31:[1,43],32:[1,44],33:40,34:46,35:[1,47],38:26},{18:[2,26]},{18:[2,30],28:[2,30],30:[2,30],31:[2,30],32:[2,30],35:[2,30]},{18:[2,36],34:59,35:[1,60]},{18:[2,31],28:[2,31],30:[2,31],31:[2,31],32:[2,31],35:[2,31]},{18:[2,32],28:[2,32],30:[2,32],31:[2,32],32:[2,32],35:[2,32]},{18:[2,33],28:[2,33],30:[2,33],31:[2,33],32:[2,33],35:[2,33]},{18:[2,34],28:[2,34],30:[2,34],31:[2,34],32:[2,34],35:[2,34]},{18:[2,35],28:[2,35],30:[2,35],31:[2,35],32:[2,35],35:[2,35]},{18:[2,38],35:[2,38]},{18:[2,47],28:[2,47],30:[2,47],31:[2,47],32:[2,47],35:[2,47],36:[1,61],39:[2,47]},{35:[1,62]},{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]},{21:63,35:[1,27],38:26},{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]},{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,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,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],24:[2,21]},{18:[1,64]},{18:[2,24]},{18:[2,29],28:[2,29],30:[2,29],31:[2,29],32:[2,29],35:[2,29]},{18:[2,37],35:[2,37]},{36:[1,61]},{21:65,28:[1,69],30:[1,66],31:[1,67],32:[1,68],35:[1,27],38:26},{18:[2,46],28:[2,46],30:[2,46],31:[2,46],32:[2,46],35:[2,46],39:[2,46]},{18:[1,70]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],24:[2,22]},{18:[2,39],35:[2,39]},{18:[2,40],35:[2,40]},{18:[2,41],35:[2,41]},{18:[2,42],35:[2,42]},{18:[2,43],35:[2,43]},{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]}],
288
- defaultActions: {17:[2,1],25:[2,28],38:[2,26],57:[2,24]},
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]},
289
215
  parseError: function parseError(str, hash) {
290
216
  throw new Error(str);
291
217
  },
@@ -566,241 +492,250 @@ lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_STA
566
492
 
567
493
  var YYSTATE=YY_START;
568
494
  switch($avoiding_name_collisions) {
569
- case 0: yy_.yytext = "\\"; return 14;
570
- break;
571
- case 1:
495
+ case 0:
572
496
  if(yy_.yytext.slice(-1) !== "\\") this.begin("mu");
573
497
  if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu");
574
498
  if(yy_.yytext) return 14;
575
499
 
576
500
  break;
577
- case 2: return 14;
501
+ case 1: return 14;
578
502
  break;
579
- case 3:
503
+ case 2:
580
504
  if(yy_.yytext.slice(-1) !== "\\") this.popState();
581
505
  if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1);
582
506
  return 14;
583
507
 
584
508
  break;
585
- case 4: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15;
586
- break;
587
- case 5: this.begin("par"); return 24;
588
- break;
589
- case 6: return 16;
590
- break;
591
- case 7: return 20;
592
- break;
593
- case 8: return 19;
509
+ case 3: return 24;
594
510
  break;
595
- case 9: return 19;
511
+ case 4: return 16;
596
512
  break;
597
- case 10: return 23;
513
+ case 5: return 20;
598
514
  break;
599
- case 11: return 23;
515
+ case 6: return 19;
600
516
  break;
601
- case 12: this.popState(); this.begin('com');
517
+ case 7: return 19;
602
518
  break;
603
- case 13: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
519
+ case 8: return 23;
604
520
  break;
605
- case 14: return 22;
521
+ case 9: return 23;
606
522
  break;
607
- case 15: return 36;
523
+ case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
608
524
  break;
609
- case 16: return 35;
525
+ case 11: return 22;
610
526
  break;
611
- case 17: return 35;
527
+ case 12: return 35;
612
528
  break;
613
- case 18: return 39;
529
+ case 13: return 34;
614
530
  break;
615
- case 19: /*ignore whitespace*/
531
+ case 14: return 34;
616
532
  break;
617
- case 20: this.popState(); return 18;
533
+ case 15: return 37;
618
534
  break;
619
- case 21: this.popState(); return 18;
535
+ case 16: /*ignore whitespace*/
620
536
  break;
621
- case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30;
537
+ case 17: this.popState(); return 18;
622
538
  break;
623
- case 23: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30;
539
+ case 18: this.popState(); return 18;
624
540
  break;
625
- case 24: yy_.yytext = yy_.yytext.substr(1); return 28;
541
+ case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29;
626
542
  break;
627
- case 25: return 32;
543
+ case 20: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29;
628
544
  break;
629
- case 26: return 32;
545
+ case 21: yy_.yytext = yy_.yytext.substr(1); return 27;
630
546
  break;
631
- case 27: return 31;
547
+ case 22: return 31;
632
548
  break;
633
- case 28: return 35;
549
+ case 23: return 31;
634
550
  break;
635
- case 29: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35;
551
+ case 24: return 30;
636
552
  break;
637
- case 30: return 'INVALID';
553
+ case 25: return 34;
638
554
  break;
639
- case 31: /*ignore whitespace*/
555
+ case 26: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 34;
640
556
  break;
641
- case 32: this.popState(); return 37;
557
+ case 27: return 'INVALID';
642
558
  break;
643
- case 33: return 5;
559
+ case 28: return 5;
644
560
  break;
645
561
  }
646
562
  };
647
- lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$:\-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$\-\/]+)/,/^(?:$)/];
648
- lexer.conditions = {"mu":{"rules":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,33],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"par":{"rules":[31,32],"inclusive":false},"INITIAL":{"rules":[0,1,2,33],"inclusive":true}};
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}};
649
565
  return lexer;})();
650
566
  parser.lexer = lexer;
651
567
  function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;
652
568
  return new Parser;
653
- })();;
569
+ })();
570
+ if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
571
+ exports.parser = handlebars;
572
+ exports.Parser = handlebars.Parser;
573
+ exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); };
574
+ exports.main = function commonjsMain(args) {
575
+ if (!args[1])
576
+ throw new Error('Usage: '+args[0]+' FILE');
577
+ var source, cwd;
578
+ if (typeof process !== 'undefined') {
579
+ source = require('fs').readFileSync(require('path').resolve(args[1]), "utf8");
580
+ } else {
581
+ source = require("file").path(require("file").cwd()).join(args[1]).read({charset: "utf-8"});
582
+ }
583
+ return exports.parser.parse(source);
584
+ };
585
+ if (typeof module !== 'undefined' && require.main === module) {
586
+ exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
587
+ }
588
+ };
589
+ ;
654
590
  // lib/handlebars/compiler/base.js
655
-
656
591
  Handlebars.Parser = handlebars;
657
592
 
658
- Handlebars.parse = function(input) {
593
+ Handlebars.parse = function(string) {
594
+ Handlebars.Parser.yy = Handlebars.AST;
595
+ return Handlebars.Parser.parse(string);
596
+ };
659
597
 
660
- // Just return if an already-compile AST was passed in.
661
- if(input.constructor === Handlebars.AST.ProgramNode) { return input; }
598
+ Handlebars.print = function(ast) {
599
+ return new Handlebars.PrintVisitor().accept(ast);
600
+ };
662
601
 
663
- Handlebars.Parser.yy = Handlebars.AST;
664
- return Handlebars.Parser.parse(input);
602
+ Handlebars.logger = {
603
+ DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
604
+
605
+ // override in the host environment
606
+ log: function(level, str) {}
665
607
  };
608
+
609
+ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
666
610
  ;
667
611
  // lib/handlebars/compiler/ast.js
668
- Handlebars.AST = {};
612
+ (function() {
669
613
 
670
- Handlebars.AST.ProgramNode = function(statements, inverse) {
671
- this.type = "program";
672
- this.statements = statements;
673
- if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
674
- };
614
+ Handlebars.AST = {};
675
615
 
676
- Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
677
- this.type = "mustache";
678
- this.escaped = !unescaped;
679
- this.hash = hash;
616
+ Handlebars.AST.ProgramNode = function(statements, inverse) {
617
+ this.type = "program";
618
+ this.statements = statements;
619
+ if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
620
+ };
680
621
 
681
- var id = this.id = rawParams[0];
682
- var params = this.params = rawParams.slice(1);
622
+ Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
623
+ this.type = "mustache";
624
+ this.escaped = !unescaped;
625
+ this.hash = hash;
683
626
 
684
- // a mustache is an eligible helper if:
685
- // * its id is simple (a single part, not `this` or `..`)
686
- var eligibleHelper = this.eligibleHelper = id.isSimple;
627
+ var id = this.id = rawParams[0];
628
+ var params = this.params = rawParams.slice(1);
687
629
 
688
- // a mustache is definitely a helper if:
689
- // * it is an eligible helper, and
690
- // * it has at least one parameter or hash segment
691
- this.isHelper = eligibleHelper && (params.length || hash);
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;
692
633
 
693
- // if a mustache is an eligible helper but not a definite
694
- // helper, it is ambiguous, and will be resolved in a later
695
- // pass or at runtime.
696
- };
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);
697
638
 
698
- Handlebars.AST.PartialNode = function(partialName, context) {
699
- this.type = "partial";
700
- this.partialName = partialName;
701
- this.context = context;
702
- };
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.
642
+ };
643
+
644
+ Handlebars.AST.PartialNode = function(id, context) {
645
+ this.type = "partial";
646
+
647
+ // TODO: disallow complex IDs
648
+
649
+ this.id = id;
650
+ this.context = context;
651
+ };
703
652
 
704
- Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
705
653
  var verifyMatch = function(open, close) {
706
654
  if(open.original !== close.original) {
707
655
  throw new Handlebars.Exception(open.original + " doesn't match " + close.original);
708
656
  }
709
657
  };
710
658
 
711
- verifyMatch(mustache.id, close);
712
- this.type = "block";
713
- this.mustache = mustache;
714
- this.program = program;
715
- this.inverse = inverse;
659
+ Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
660
+ verifyMatch(mustache.id, close);
661
+ this.type = "block";
662
+ this.mustache = mustache;
663
+ this.program = program;
664
+ this.inverse = inverse;
716
665
 
717
- if (this.inverse && !this.program) {
718
- this.isInverse = true;
719
- }
720
- };
666
+ if (this.inverse && !this.program) {
667
+ this.isInverse = true;
668
+ }
669
+ };
721
670
 
722
- Handlebars.AST.ContentNode = function(string) {
723
- this.type = "content";
724
- this.string = string;
725
- };
671
+ Handlebars.AST.ContentNode = function(string) {
672
+ this.type = "content";
673
+ this.string = string;
674
+ };
726
675
 
727
- Handlebars.AST.HashNode = function(pairs) {
728
- this.type = "hash";
729
- this.pairs = pairs;
730
- };
676
+ Handlebars.AST.HashNode = function(pairs) {
677
+ this.type = "hash";
678
+ this.pairs = pairs;
679
+ };
731
680
 
732
- Handlebars.AST.IdNode = function(parts) {
733
- this.type = "ID";
734
- this.original = parts.join(".");
681
+ Handlebars.AST.IdNode = function(parts) {
682
+ this.type = "ID";
683
+ this.original = parts.join(".");
735
684
 
736
- var dig = [], depth = 0;
685
+ var dig = [], depth = 0;
737
686
 
738
- for(var i=0,l=parts.length; i<l; i++) {
739
- var part = parts[i];
687
+ for(var i=0,l=parts.length; i<l; i++) {
688
+ var part = parts[i];
740
689
 
741
- if (part === ".." || part === "." || part === "this") {
742
- if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + this.original); }
743
- else if (part === "..") { depth++; }
744
- else { this.isScoped = true; }
690
+ if(part === "..") { depth++; }
691
+ else if(part === "." || part === "this") { this.isScoped = true; }
692
+ else { dig.push(part); }
745
693
  }
746
- else { dig.push(part); }
747
- }
748
-
749
- this.parts = dig;
750
- this.string = dig.join('.');
751
- this.depth = depth;
752
694
 
753
- // an ID is simple if it only has one part, and that part is not
754
- // `..` or `this`.
755
- this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
695
+ this.parts = dig;
696
+ this.string = dig.join('.');
697
+ this.depth = depth;
756
698
 
757
- this.stringModeValue = this.string;
758
- };
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
+ };
759
703
 
760
- Handlebars.AST.PartialNameNode = function(name) {
761
- this.type = "PARTIAL_NAME";
762
- this.name = name;
763
- };
704
+ Handlebars.AST.DataNode = function(id) {
705
+ this.type = "DATA";
706
+ this.id = id;
707
+ };
764
708
 
765
- Handlebars.AST.DataNode = function(id) {
766
- this.type = "DATA";
767
- this.id = id;
768
- };
709
+ Handlebars.AST.StringNode = function(string) {
710
+ this.type = "STRING";
711
+ this.string = string;
712
+ };
769
713
 
770
- Handlebars.AST.StringNode = function(string) {
771
- this.type = "STRING";
772
- this.string = string;
773
- this.stringModeValue = string;
774
- };
714
+ Handlebars.AST.IntegerNode = function(integer) {
715
+ this.type = "INTEGER";
716
+ this.integer = integer;
717
+ };
775
718
 
776
- Handlebars.AST.IntegerNode = function(integer) {
777
- this.type = "INTEGER";
778
- this.integer = integer;
779
- this.stringModeValue = Number(integer);
780
- };
719
+ Handlebars.AST.BooleanNode = function(bool) {
720
+ this.type = "BOOLEAN";
721
+ this.bool = bool;
722
+ };
781
723
 
782
- Handlebars.AST.BooleanNode = function(bool) {
783
- this.type = "BOOLEAN";
784
- this.bool = bool;
785
- this.stringModeValue = bool === "true";
786
- };
724
+ Handlebars.AST.CommentNode = function(comment) {
725
+ this.type = "comment";
726
+ this.comment = comment;
727
+ };
787
728
 
788
- Handlebars.AST.CommentNode = function(comment) {
789
- this.type = "comment";
790
- this.comment = comment;
791
- };
792
- ;
729
+ })();;
793
730
  // lib/handlebars/utils.js
794
-
795
- var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
796
-
797
731
  Handlebars.Exception = function(message) {
798
732
  var tmp = Error.prototype.constructor.apply(this, arguments);
799
733
 
800
- // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
801
- for (var idx = 0; idx < errorProps.length; idx++) {
802
- this[errorProps[idx]] = tmp[errorProps[idx]];
734
+ for (var p in tmp) {
735
+ if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; }
803
736
  }
737
+
738
+ this.message = tmp.message;
804
739
  };
805
740
  Handlebars.Exception.prototype = new Error();
806
741
 
@@ -812,1326 +747,1101 @@ Handlebars.SafeString.prototype.toString = function() {
812
747
  return this.string.toString();
813
748
  };
814
749
 
815
- var escape = {
816
- "&": "&amp;",
817
- "<": "&lt;",
818
- ">": "&gt;",
819
- '"': "&quot;",
820
- "'": "&#x27;",
821
- "`": "&#x60;"
822
- };
750
+ (function() {
751
+ var escape = {
752
+ "&": "&amp;",
753
+ "<": "&lt;",
754
+ ">": "&gt;",
755
+ '"': "&quot;",
756
+ "'": "&#x27;",
757
+ "`": "&#x60;"
758
+ };
823
759
 
824
- var badChars = /[&<>"'`]/g;
825
- var possible = /[&<>"'`]/;
760
+ var badChars = /[&<>"'`]/g;
761
+ var possible = /[&<>"'`]/;
826
762
 
827
- var escapeChar = function(chr) {
828
- return escape[chr] || "&amp;";
829
- };
763
+ var escapeChar = function(chr) {
764
+ return escape[chr] || "&amp;";
765
+ };
830
766
 
831
- Handlebars.Utils = {
832
- extend: function(obj, value) {
833
- for(var key in value) {
834
- if(value.hasOwnProperty(key)) {
835
- obj[key] = value[key];
767
+ Handlebars.Utils = {
768
+ escapeExpression: function(string) {
769
+ // don't escape SafeStrings, since they're already safe
770
+ if (string instanceof Handlebars.SafeString) {
771
+ return string.toString();
772
+ } else if (string == null || string === false) {
773
+ return "";
836
774
  }
837
- }
838
- },
839
-
840
- escapeExpression: function(string) {
841
- // don't escape SafeStrings, since they're already safe
842
- if (string instanceof Handlebars.SafeString) {
843
- return string.toString();
844
- } else if (string == null || string === false) {
845
- return "";
846
- }
847
-
848
- // Force a string conversion as this will be done by the append regardless and
849
- // the regex test will do this transparently behind the scenes, causing issues if
850
- // an object's to string has escaped characters in it.
851
- string = string.toString();
852
775
 
853
- if(!possible.test(string)) { return string; }
854
- return string.replace(badChars, escapeChar);
855
- },
776
+ if(!possible.test(string)) { return string; }
777
+ return string.replace(badChars, escapeChar);
778
+ },
856
779
 
857
- isEmpty: function(value) {
858
- if (!value && value !== 0) {
859
- return true;
860
- } else if(toString.call(value) === "[object Array]" && value.length === 0) {
861
- return true;
862
- } else {
863
- return false;
780
+ isEmpty: function(value) {
781
+ if (typeof value === "undefined") {
782
+ return true;
783
+ } else if (value === null) {
784
+ return true;
785
+ } else if (value === false) {
786
+ return true;
787
+ } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
788
+ return true;
789
+ } else {
790
+ return false;
791
+ }
864
792
  }
865
- }
866
- };
867
- ;
793
+ };
794
+ })();;
868
795
  // lib/handlebars/compiler/compiler.js
869
796
 
870
797
  /*jshint eqnull:true*/
871
- var Compiler = Handlebars.Compiler = function() {};
872
- var JavaScriptCompiler = Handlebars.JavaScriptCompiler = function() {};
798
+ Handlebars.Compiler = function() {};
799
+ Handlebars.JavaScriptCompiler = function() {};
873
800
 
874
- // the foundHelper register will disambiguate helper lookup from finding a
875
- // function in a context. This is necessary for mustache compatibility, which
876
- // requires that context functions in blocks are evaluated by blockHelperMissing,
877
- // and then proceed as if the resulting value was provided to blockHelperMissing.
801
+ (function(Compiler, JavaScriptCompiler) {
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.
878
806
 
879
- Compiler.prototype = {
880
- compiler: Compiler,
807
+ Compiler.prototype = {
808
+ compiler: Compiler,
881
809
 
882
- disassemble: function() {
883
- var opcodes = this.opcodes, opcode, out = [], params, param;
810
+ disassemble: function() {
811
+ var opcodes = this.opcodes, opcode, out = [], params, param;
884
812
 
885
- for (var i=0, l=opcodes.length; i<l; i++) {
886
- opcode = opcodes[i];
813
+ for (var i=0, l=opcodes.length; i<l; i++) {
814
+ opcode = opcodes[i];
887
815
 
888
- if (opcode.opcode === 'DECLARE') {
889
- out.push("DECLARE " + opcode.name + "=" + opcode.value);
890
- } else {
891
- params = [];
892
- for (var j=0; j<opcode.args.length; j++) {
893
- param = opcode.args[j];
894
- if (typeof param === "string") {
895
- param = "\"" + param.replace("\n", "\\n") + "\"";
816
+ if (opcode.opcode === 'DECLARE') {
817
+ out.push("DECLARE " + opcode.name + "=" + opcode.value);
818
+ } else {
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") + "\"";
824
+ }
825
+ params.push(param);
896
826
  }
897
- params.push(param);
827
+ out.push(opcode.opcode + " " + params.join(" "));
898
828
  }
899
- out.push(opcode.opcode + " " + params.join(" "));
900
829
  }
901
- }
902
830
 
903
- return out.join("\n");
904
- },
905
- equals: function(other) {
906
- var len = this.opcodes.length;
907
- if (other.opcodes.length !== len) {
908
- return false;
909
- }
831
+ return out.join("\n");
832
+ },
910
833
 
911
- for (var i = 0; i < len; i++) {
912
- var opcode = this.opcodes[i],
913
- otherOpcode = other.opcodes[i];
914
- if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
915
- return false;
916
- }
917
- for (var j = 0; j < opcode.args.length; j++) {
918
- if (opcode.args[j] !== otherOpcode.args[j]) {
919
- return false;
834
+ guid: 0,
835
+
836
+ compile: function(program, options) {
837
+ this.children = [];
838
+ this.depths = {list: []};
839
+ this.options = options;
840
+
841
+ // These changes will propagate to the other compiler components
842
+ var knownHelpers = this.options.knownHelpers;
843
+ this.options.knownHelpers = {
844
+ 'helperMissing': true,
845
+ 'blockHelperMissing': true,
846
+ 'each': true,
847
+ 'if': true,
848
+ 'unless': true,
849
+ 'with': true,
850
+ 'log': true
851
+ };
852
+ if (knownHelpers) {
853
+ for (var name in knownHelpers) {
854
+ this.options.knownHelpers[name] = knownHelpers[name];
920
855
  }
921
856
  }
922
- }
923
-
924
- len = this.children.length;
925
- if (other.children.length !== len) {
926
- return false;
927
- }
928
- for (i = 0; i < len; i++) {
929
- if (!this.children[i].equals(other.children[i])) {
930
- return false;
931
- }
932
- }
933
-
934
- return true;
935
- },
936
857
 
937
- guid: 0,
938
-
939
- compile: function(program, options) {
940
- this.children = [];
941
- this.depths = {list: []};
942
- this.options = options;
943
-
944
- // These changes will propagate to the other compiler components
945
- var knownHelpers = this.options.knownHelpers;
946
- this.options.knownHelpers = {
947
- 'helperMissing': true,
948
- 'blockHelperMissing': true,
949
- 'each': true,
950
- 'if': true,
951
- 'unless': true,
952
- 'with': true,
953
- 'log': true
954
- };
955
- if (knownHelpers) {
956
- for (var name in knownHelpers) {
957
- this.options.knownHelpers[name] = knownHelpers[name];
958
- }
959
- }
858
+ return this.program(program);
859
+ },
960
860
 
961
- return this.program(program);
962
- },
861
+ accept: function(node) {
862
+ return this[node.type](node);
863
+ },
963
864
 
964
- accept: function(node) {
965
- return this[node.type](node);
966
- },
865
+ program: function(program) {
866
+ var statements = program.statements, statement;
867
+ this.opcodes = [];
967
868
 
968
- program: function(program) {
969
- var statements = program.statements, statement;
970
- this.opcodes = [];
869
+ for(var i=0, l=statements.length; i<l; i++) {
870
+ statement = statements[i];
871
+ this[statement.type](statement);
872
+ }
873
+ this.isSimple = l === 1;
971
874
 
972
- for(var i=0, l=statements.length; i<l; i++) {
973
- statement = statements[i];
974
- this[statement.type](statement);
975
- }
976
- this.isSimple = l === 1;
875
+ this.depths.list = this.depths.list.sort(function(a, b) {
876
+ return a - b;
877
+ });
977
878
 
978
- this.depths.list = this.depths.list.sort(function(a, b) {
979
- return a - b;
980
- });
879
+ return this;
880
+ },
981
881
 
982
- return this;
983
- },
882
+ compileProgram: function(program) {
883
+ var result = new this.compiler().compile(program, this.options);
884
+ var guid = this.guid++, depth;
984
885
 
985
- compileProgram: function(program) {
986
- var result = new this.compiler().compile(program, this.options);
987
- var guid = this.guid++, depth;
886
+ this.usePartial = this.usePartial || result.usePartial;
988
887
 
989
- this.usePartial = this.usePartial || result.usePartial;
888
+ this.children[guid] = result;
990
889
 
991
- this.children[guid] = result;
890
+ for(var i=0, l=result.depths.list.length; i<l; i++) {
891
+ depth = result.depths.list[i];
992
892
 
993
- for(var i=0, l=result.depths.list.length; i<l; i++) {
994
- depth = result.depths.list[i];
893
+ if(depth < 2) { continue; }
894
+ else { this.addDepth(depth - 1); }
895
+ }
995
896
 
996
- if(depth < 2) { continue; }
997
- else { this.addDepth(depth - 1); }
998
- }
897
+ return guid;
898
+ },
999
899
 
1000
- return guid;
1001
- },
900
+ block: function(block) {
901
+ var mustache = block.mustache,
902
+ program = block.program,
903
+ inverse = block.inverse;
1002
904
 
1003
- block: function(block) {
1004
- var mustache = block.mustache,
1005
- program = block.program,
1006
- inverse = block.inverse;
905
+ if (program) {
906
+ program = this.compileProgram(program);
907
+ }
1007
908
 
1008
- if (program) {
1009
- program = this.compileProgram(program);
1010
- }
909
+ if (inverse) {
910
+ inverse = this.compileProgram(inverse);
911
+ }
1011
912
 
1012
- if (inverse) {
1013
- inverse = this.compileProgram(inverse);
1014
- }
913
+ var type = this.classifyMustache(mustache);
1015
914
 
1016
- var type = this.classifyMustache(mustache);
915
+ if (type === "helper") {
916
+ this.helperMustache(mustache, program, inverse);
917
+ } else if (type === "simple") {
918
+ this.simpleMustache(mustache);
1017
919
 
1018
- if (type === "helper") {
1019
- this.helperMustache(mustache, program, inverse);
1020
- } else if (type === "simple") {
1021
- this.simpleMustache(mustache);
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
+ }
1022
936
 
1023
- // now that the simple mustache is resolved, we need to
1024
- // evaluate it by executing `blockHelperMissing`
1025
- this.opcode('pushProgram', program);
1026
- this.opcode('pushProgram', inverse);
1027
- this.opcode('emptyHash');
1028
- this.opcode('blockValue');
1029
- } else {
1030
- this.ambiguousMustache(mustache, program, inverse);
937
+ this.opcode('append');
938
+ },
1031
939
 
1032
- // now that the simple mustache is resolved, we need to
1033
- // evaluate it by executing `blockHelperMissing`
1034
- this.opcode('pushProgram', program);
1035
- this.opcode('pushProgram', inverse);
1036
- this.opcode('emptyHash');
1037
- this.opcode('ambiguousBlockValue');
1038
- }
940
+ hash: function(hash) {
941
+ var pairs = hash.pairs, pair, val;
1039
942
 
1040
- this.opcode('append');
1041
- },
943
+ this.opcode('push', '{}');
1042
944
 
1043
- hash: function(hash) {
1044
- var pairs = hash.pairs, pair, val;
945
+ for(var i=0, l=pairs.length; i<l; i++) {
946
+ pair = pairs[i];
947
+ val = pair[1];
1045
948
 
1046
- this.opcode('pushHash');
949
+ this.accept(val);
950
+ this.opcode('assignToHash', pair[0]);
951
+ }
952
+ },
1047
953
 
1048
- for(var i=0, l=pairs.length; i<l; i++) {
1049
- pair = pairs[i];
1050
- val = pair[1];
954
+ partial: function(partial) {
955
+ var id = partial.id;
956
+ this.usePartial = true;
1051
957
 
1052
- if (this.options.stringParams) {
1053
- if(val.depth) {
1054
- this.addDepth(val.depth);
1055
- }
1056
- this.opcode('getContext', val.depth || 0);
1057
- this.opcode('pushStringParam', val.stringModeValue, val.type);
958
+ if(partial.context) {
959
+ this.ID(partial.context);
1058
960
  } else {
1059
- this.accept(val);
961
+ this.opcode('push', 'depth0');
1060
962
  }
1061
963
 
1062
- this.opcode('assignToHash', pair[0]);
1063
- }
1064
- this.opcode('popHash');
1065
- },
964
+ this.opcode('invokePartial', id.original);
965
+ this.opcode('append');
966
+ },
1066
967
 
1067
- partial: function(partial) {
1068
- var partialName = partial.partialName;
1069
- this.usePartial = true;
968
+ content: function(content) {
969
+ this.opcode('appendContent', content.string);
970
+ },
1070
971
 
1071
- if(partial.context) {
1072
- this.ID(partial.context);
1073
- } else {
1074
- this.opcode('push', 'depth0');
1075
- }
972
+ mustache: function(mustache) {
973
+ var options = this.options;
974
+ var type = this.classifyMustache(mustache);
1076
975
 
1077
- this.opcode('invokePartial', partialName.name);
1078
- this.opcode('append');
1079
- },
976
+ if (type === "simple") {
977
+ this.simpleMustache(mustache);
978
+ } else if (type === "helper") {
979
+ this.helperMustache(mustache);
980
+ } else {
981
+ this.ambiguousMustache(mustache);
982
+ }
1080
983
 
1081
- content: function(content) {
1082
- this.opcode('appendContent', content.string);
1083
- },
984
+ if(mustache.escaped && !options.noEscape) {
985
+ this.opcode('appendEscaped');
986
+ } else {
987
+ this.opcode('append');
988
+ }
989
+ },
1084
990
 
1085
- mustache: function(mustache) {
1086
- var options = this.options;
1087
- var type = this.classifyMustache(mustache);
991
+ ambiguousMustache: function(mustache, program, inverse) {
992
+ var id = mustache.id, name = id.parts[0];
1088
993
 
1089
- if (type === "simple") {
1090
- this.simpleMustache(mustache);
1091
- } else if (type === "helper") {
1092
- this.helperMustache(mustache);
1093
- } else {
1094
- this.ambiguousMustache(mustache);
1095
- }
994
+ this.opcode('getContext', id.depth);
1096
995
 
1097
- if(mustache.escaped && !options.noEscape) {
1098
- this.opcode('appendEscaped');
1099
- } else {
1100
- this.opcode('append');
1101
- }
1102
- },
996
+ this.opcode('pushProgram', program);
997
+ this.opcode('pushProgram', inverse);
1103
998
 
1104
- ambiguousMustache: function(mustache, program, inverse) {
1105
- var id = mustache.id,
1106
- name = id.parts[0],
1107
- isBlock = program != null || inverse != null;
999
+ this.opcode('invokeAmbiguous', name);
1000
+ },
1108
1001
 
1109
- this.opcode('getContext', id.depth);
1002
+ simpleMustache: function(mustache, program, inverse) {
1003
+ var id = mustache.id;
1110
1004
 
1111
- this.opcode('pushProgram', program);
1112
- this.opcode('pushProgram', inverse);
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
+ }
1113
1015
 
1114
- this.opcode('invokeAmbiguous', name, isBlock);
1115
- },
1016
+ this.opcode('resolvePossibleLambda');
1017
+ },
1116
1018
 
1117
- simpleMustache: function(mustache) {
1118
- var id = mustache.id;
1019
+ helperMustache: function(mustache, program, inverse) {
1020
+ var params = this.setupFullMustacheParams(mustache, program, inverse),
1021
+ name = mustache.id.parts[0];
1119
1022
 
1120
- if (id.type === 'DATA') {
1121
- this.DATA(id);
1122
- } else if (id.parts.length) {
1123
- this.ID(id);
1124
- } else {
1125
- // Simplified ID for `this`
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
+
1032
+ ID: function(id) {
1126
1033
  this.addDepth(id.depth);
1127
1034
  this.opcode('getContext', id.depth);
1128
- this.opcode('pushContext');
1129
- }
1130
1035
 
1131
- this.opcode('resolvePossibleLambda');
1132
- },
1036
+ var name = id.parts[0];
1037
+ if (!name) {
1038
+ this.opcode('pushContext');
1039
+ } else {
1040
+ this.opcode('lookupOnContext', id.parts[0]);
1041
+ }
1133
1042
 
1134
- helperMustache: function(mustache, program, inverse) {
1135
- var params = this.setupFullMustacheParams(mustache, program, inverse),
1136
- name = mustache.id.parts[0];
1043
+ for(var i=1, l=id.parts.length; i<l; i++) {
1044
+ this.opcode('lookup', id.parts[i]);
1045
+ }
1046
+ },
1137
1047
 
1138
- if (this.options.knownHelpers[name]) {
1139
- this.opcode('invokeKnownHelper', params.length, name);
1140
- } else if (this.options.knownHelpersOnly) {
1141
- throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
1142
- } else {
1143
- this.opcode('invokeHelper', params.length, name);
1144
- }
1145
- },
1048
+ DATA: function(data) {
1049
+ this.options.data = true;
1050
+ this.opcode('lookupData', data.id);
1051
+ },
1052
+
1053
+ STRING: function(string) {
1054
+ this.opcode('pushString', string.string);
1055
+ },
1146
1056
 
1147
- ID: function(id) {
1148
- this.addDepth(id.depth);
1149
- this.opcode('getContext', id.depth);
1057
+ INTEGER: function(integer) {
1058
+ this.opcode('pushLiteral', integer.integer);
1059
+ },
1150
1060
 
1151
- var name = id.parts[0];
1152
- if (!name) {
1153
- this.opcode('pushContext');
1154
- } else {
1155
- this.opcode('lookupOnContext', id.parts[0]);
1156
- }
1061
+ BOOLEAN: function(bool) {
1062
+ this.opcode('pushLiteral', bool.bool);
1063
+ },
1157
1064
 
1158
- for(var i=1, l=id.parts.length; i<l; i++) {
1159
- this.opcode('lookup', id.parts[i]);
1160
- }
1161
- },
1065
+ comment: function() {},
1162
1066
 
1163
- DATA: function(data) {
1164
- this.options.data = true;
1165
- this.opcode('lookupData', data.id);
1166
- },
1067
+ // HELPERS
1068
+ opcode: function(name) {
1069
+ this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
1070
+ },
1167
1071
 
1168
- STRING: function(string) {
1169
- this.opcode('pushString', string.string);
1170
- },
1072
+ declare: function(name, value) {
1073
+ this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
1074
+ },
1171
1075
 
1172
- INTEGER: function(integer) {
1173
- this.opcode('pushLiteral', integer.integer);
1174
- },
1076
+ addDepth: function(depth) {
1077
+ if(isNaN(depth)) { throw new Error("EWOT"); }
1078
+ if(depth === 0) { return; }
1175
1079
 
1176
- BOOLEAN: function(bool) {
1177
- this.opcode('pushLiteral', bool.bool);
1178
- },
1080
+ if(!this.depths[depth]) {
1081
+ this.depths[depth] = true;
1082
+ this.depths.list.push(depth);
1083
+ }
1084
+ },
1179
1085
 
1180
- comment: function() {},
1086
+ classifyMustache: function(mustache) {
1087
+ var isHelper = mustache.isHelper;
1088
+ var isEligible = mustache.eligibleHelper;
1089
+ var options = this.options;
1181
1090
 
1182
- // HELPERS
1183
- opcode: function(name) {
1184
- this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
1185
- },
1091
+ // if ambiguous, we can possibly resolve the ambiguity now
1092
+ if (isEligible && !isHelper) {
1093
+ var name = mustache.id.parts[0];
1186
1094
 
1187
- declare: function(name, value) {
1188
- this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
1189
- },
1095
+ if (options.knownHelpers[name]) {
1096
+ isHelper = true;
1097
+ } else if (options.knownHelpersOnly) {
1098
+ isEligible = false;
1099
+ }
1100
+ }
1190
1101
 
1191
- addDepth: function(depth) {
1192
- if(isNaN(depth)) { throw new Error("EWOT"); }
1193
- if(depth === 0) { return; }
1102
+ if (isHelper) { return "helper"; }
1103
+ else if (isEligible) { return "ambiguous"; }
1104
+ else { return "simple"; }
1105
+ },
1194
1106
 
1195
- if(!this.depths[depth]) {
1196
- this.depths[depth] = true;
1197
- this.depths.list.push(depth);
1198
- }
1199
- },
1107
+ pushParams: function(params) {
1108
+ var i = params.length, param;
1200
1109
 
1201
- classifyMustache: function(mustache) {
1202
- var isHelper = mustache.isHelper;
1203
- var isEligible = mustache.eligibleHelper;
1204
- var options = this.options;
1110
+ while(i--) {
1111
+ param = params[i];
1205
1112
 
1206
- // if ambiguous, we can possibly resolve the ambiguity now
1207
- if (isEligible && !isHelper) {
1208
- var name = mustache.id.parts[0];
1113
+ if(this.options.stringParams) {
1114
+ if(param.depth) {
1115
+ this.addDepth(param.depth);
1116
+ }
1209
1117
 
1210
- if (options.knownHelpers[name]) {
1211
- isHelper = true;
1212
- } else if (options.knownHelpersOnly) {
1213
- isEligible = false;
1118
+ this.opcode('getContext', param.depth || 0);
1119
+ this.opcode('pushStringParam', param.string);
1120
+ } else {
1121
+ this[param.type](param);
1122
+ }
1214
1123
  }
1215
- }
1124
+ },
1216
1125
 
1217
- if (isHelper) { return "helper"; }
1218
- else if (isEligible) { return "ambiguous"; }
1219
- else { return "simple"; }
1220
- },
1126
+ setupMustacheParams: function(mustache) {
1127
+ var params = mustache.params;
1128
+ this.pushParams(params);
1221
1129
 
1222
- pushParams: function(params) {
1223
- var i = params.length, param;
1130
+ if(mustache.hash) {
1131
+ this.hash(mustache.hash);
1132
+ } else {
1133
+ this.opcode('pushLiteral', '{}');
1134
+ }
1224
1135
 
1225
- while(i--) {
1226
- param = params[i];
1136
+ return params;
1137
+ },
1227
1138
 
1228
- if(this.options.stringParams) {
1229
- if(param.depth) {
1230
- this.addDepth(param.depth);
1231
- }
1139
+ // this will replace setupMustacheParams when we're done
1140
+ setupFullMustacheParams: function(mustache, program, inverse) {
1141
+ var params = mustache.params;
1142
+ this.pushParams(params);
1232
1143
 
1233
- this.opcode('getContext', param.depth || 0);
1234
- this.opcode('pushStringParam', param.stringModeValue, param.type);
1144
+ this.opcode('pushProgram', program);
1145
+ this.opcode('pushProgram', inverse);
1146
+
1147
+ if(mustache.hash) {
1148
+ this.hash(mustache.hash);
1235
1149
  } else {
1236
- this[param.type](param);
1150
+ this.opcode('pushLiteral', '{}');
1237
1151
  }
1238
- }
1239
- },
1240
1152
 
1241
- setupMustacheParams: function(mustache) {
1242
- var params = mustache.params;
1243
- this.pushParams(params);
1244
-
1245
- if(mustache.hash) {
1246
- this.hash(mustache.hash);
1247
- } else {
1248
- this.opcode('emptyHash');
1153
+ return params;
1249
1154
  }
1155
+ };
1250
1156
 
1251
- return params;
1252
- },
1157
+ var Literal = function(value) {
1158
+ this.value = value;
1159
+ };
1253
1160
 
1254
- // this will replace setupMustacheParams when we're done
1255
- setupFullMustacheParams: function(mustache, program, inverse) {
1256
- var params = mustache.params;
1257
- this.pushParams(params);
1161
+ JavaScriptCompiler.prototype = {
1162
+ // PUBLIC API: You can override these methods in a subclass to provide
1163
+ // alternative compiled forms for name lookup and buffering semantics
1164
+ nameLookup: function(parent, name, type) {
1165
+ if (/^[0-9]+$/.test(name)) {
1166
+ return parent + "[" + name + "]";
1167
+ } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1168
+ return parent + "." + name;
1169
+ }
1170
+ else {
1171
+ return parent + "['" + name + "']";
1172
+ }
1173
+ },
1258
1174
 
1259
- this.opcode('pushProgram', program);
1260
- this.opcode('pushProgram', inverse);
1175
+ appendToBuffer: function(string) {
1176
+ if (this.environment.isSimple) {
1177
+ return "return " + string + ";";
1178
+ } else {
1179
+ return "buffer += " + string + ";";
1180
+ }
1181
+ },
1261
1182
 
1262
- if(mustache.hash) {
1263
- this.hash(mustache.hash);
1264
- } else {
1265
- this.opcode('emptyHash');
1266
- }
1183
+ initializeBuffer: function() {
1184
+ return this.quotedString("");
1185
+ },
1267
1186
 
1268
- return params;
1269
- }
1270
- };
1187
+ namespace: "Handlebars",
1188
+ // END PUBLIC API
1271
1189
 
1272
- var Literal = function(value) {
1273
- this.value = value;
1274
- };
1190
+ compile: function(environment, options, context, asObject) {
1191
+ this.environment = environment;
1192
+ this.options = options || {};
1275
1193
 
1276
- JavaScriptCompiler.prototype = {
1277
- // PUBLIC API: You can override these methods in a subclass to provide
1278
- // alternative compiled forms for name lookup and buffering semantics
1279
- nameLookup: function(parent, name /* , type*/) {
1280
- if (/^[0-9]+$/.test(name)) {
1281
- return parent + "[" + name + "]";
1282
- } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1283
- return parent + "." + name;
1284
- }
1285
- else {
1286
- return parent + "['" + name + "']";
1287
- }
1288
- },
1194
+ Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
1289
1195
 
1290
- appendToBuffer: function(string) {
1291
- if (this.environment.isSimple) {
1292
- return "return " + string + ";";
1293
- } else {
1294
- return {
1295
- appendToBuffer: true,
1296
- content: string,
1297
- toString: function() { return "buffer += " + string + ";"; }
1196
+ this.name = this.environment.name;
1197
+ this.isChild = !!context;
1198
+ this.context = context || {
1199
+ programs: [],
1200
+ aliases: { }
1298
1201
  };
1299
- }
1300
- },
1301
1202
 
1302
- initializeBuffer: function() {
1303
- return this.quotedString("");
1304
- },
1203
+ this.preamble();
1305
1204
 
1306
- namespace: "Handlebars",
1307
- // END PUBLIC API
1205
+ this.stackSlot = 0;
1206
+ this.stackVars = [];
1207
+ this.registers = { list: [] };
1208
+ this.compileStack = [];
1308
1209
 
1309
- compile: function(environment, options, context, asObject) {
1310
- this.environment = environment;
1311
- this.options = options || {};
1210
+ this.compileChildren(environment, options);
1312
1211
 
1313
- Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
1212
+ var opcodes = environment.opcodes, opcode;
1314
1213
 
1315
- this.name = this.environment.name;
1316
- this.isChild = !!context;
1317
- this.context = context || {
1318
- programs: [],
1319
- environments: [],
1320
- aliases: { }
1321
- };
1214
+ this.i = 0;
1322
1215
 
1323
- this.preamble();
1216
+ for(l=opcodes.length; this.i<l; this.i++) {
1217
+ opcode = opcodes[this.i];
1324
1218
 
1325
- this.stackSlot = 0;
1326
- this.stackVars = [];
1327
- this.registers = { list: [] };
1328
- this.compileStack = [];
1329
- this.inlineStack = [];
1219
+ if(opcode.opcode === 'DECLARE') {
1220
+ this[opcode.name] = opcode.value;
1221
+ } else {
1222
+ this[opcode.opcode].apply(this, opcode.args);
1223
+ }
1224
+ }
1330
1225
 
1331
- this.compileChildren(environment, options);
1226
+ return this.createFunctionContext(asObject);
1227
+ },
1332
1228
 
1333
- var opcodes = environment.opcodes, opcode;
1229
+ nextOpcode: function() {
1230
+ var opcodes = this.environment.opcodes, opcode = opcodes[this.i + 1];
1231
+ return opcodes[this.i + 1];
1232
+ },
1334
1233
 
1335
- this.i = 0;
1234
+ eat: function(opcode) {
1235
+ this.i = this.i + 1;
1236
+ },
1336
1237
 
1337
- for(l=opcodes.length; this.i<l; this.i++) {
1338
- opcode = opcodes[this.i];
1238
+ preamble: function() {
1239
+ var out = [];
1339
1240
 
1340
- if(opcode.opcode === 'DECLARE') {
1341
- this[opcode.name] = opcode.value;
1241
+ if (!this.isChild) {
1242
+ var namespace = this.namespace;
1243
+ var copies = "helpers = helpers || " + namespace + ".helpers;";
1244
+ if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
1245
+ if (this.options.data) { copies = copies + " data = data || {};"; }
1246
+ out.push(copies);
1342
1247
  } else {
1343
- this[opcode.opcode].apply(this, opcode.args);
1248
+ out.push('');
1344
1249
  }
1345
- }
1346
-
1347
- return this.createFunctionContext(asObject);
1348
- },
1349
1250
 
1350
- nextOpcode: function() {
1351
- var opcodes = this.environment.opcodes;
1352
- return opcodes[this.i + 1];
1353
- },
1354
-
1355
- eat: function() {
1356
- this.i = this.i + 1;
1357
- },
1358
-
1359
- preamble: function() {
1360
- var out = [];
1361
-
1362
- if (!this.isChild) {
1363
- var namespace = this.namespace;
1364
- var copies = "helpers = helpers || " + namespace + ".helpers;";
1365
- if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
1366
- if (this.options.data) { copies = copies + " data = data || {};"; }
1367
- out.push(copies);
1368
- } else {
1369
- out.push('');
1370
- }
1371
-
1372
- if (!this.environment.isSimple) {
1373
- out.push(", buffer = " + this.initializeBuffer());
1374
- } else {
1375
- out.push("");
1376
- }
1377
-
1378
- // track the last context pushed into place to allow skipping the
1379
- // getContext opcode when it would be a noop
1380
- this.lastContext = 0;
1381
- this.source = out;
1382
- },
1251
+ if (!this.environment.isSimple) {
1252
+ out.push(", buffer = " + this.initializeBuffer());
1253
+ } else {
1254
+ out.push("");
1255
+ }
1383
1256
 
1384
- createFunctionContext: function(asObject) {
1385
- var locals = this.stackVars.concat(this.registers.list);
1257
+ // track the last context pushed into place to allow skipping the
1258
+ // getContext opcode when it would be a noop
1259
+ this.lastContext = 0;
1260
+ this.source = out;
1261
+ },
1386
1262
 
1387
- if(locals.length > 0) {
1388
- this.source[1] = this.source[1] + ", " + locals.join(", ");
1389
- }
1263
+ createFunctionContext: function(asObject) {
1264
+ var locals = this.stackVars.concat(this.registers.list);
1390
1265
 
1391
- // Generate minimizer alias mappings
1392
- if (!this.isChild) {
1393
- for (var alias in this.context.aliases) {
1394
- this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1266
+ if(locals.length > 0) {
1267
+ this.source[1] = this.source[1] + ", " + locals.join(", ");
1395
1268
  }
1396
- }
1397
1269
 
1398
- if (this.source[1]) {
1399
- this.source[1] = "var " + this.source[1].substring(2) + ";";
1400
- }
1401
-
1402
- // Merge children
1403
- if (!this.isChild) {
1404
- this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1405
- }
1270
+ // Generate minimizer alias mappings
1271
+ if (!this.isChild) {
1272
+ var aliases = [];
1273
+ for (var alias in this.context.aliases) {
1274
+ this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1275
+ }
1276
+ }
1406
1277
 
1407
- if (!this.environment.isSimple) {
1408
- this.source.push("return buffer;");
1409
- }
1278
+ if (this.source[1]) {
1279
+ this.source[1] = "var " + this.source[1].substring(2) + ";";
1280
+ }
1410
1281
 
1411
- var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1282
+ // Merge children
1283
+ if (!this.isChild) {
1284
+ this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1285
+ }
1412
1286
 
1413
- for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1414
- params.push("depth" + this.environment.depths.list[i]);
1415
- }
1287
+ if (!this.environment.isSimple) {
1288
+ this.source.push("return buffer;");
1289
+ }
1416
1290
 
1417
- // Perform a second pass over the output to merge content when possible
1418
- var source = this.mergeSource();
1291
+ var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1419
1292
 
1420
- if (!this.isChild) {
1421
- var revision = Handlebars.COMPILER_REVISION,
1422
- versions = Handlebars.REVISION_CHANGES[revision];
1423
- source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
1424
- }
1293
+ for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1294
+ params.push("depth" + this.environment.depths.list[i]);
1295
+ }
1425
1296
 
1426
- if (asObject) {
1427
- params.push(source);
1297
+ if (asObject) {
1298
+ params.push(this.source.join("\n "));
1428
1299
 
1429
- return Function.apply(this, params);
1430
- } else {
1431
- var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
1432
- Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1433
- return functionSource;
1434
- }
1435
- },
1436
- mergeSource: function() {
1437
- // WARN: We are not handling the case where buffer is still populated as the source should
1438
- // not have buffer append operations as their final action.
1439
- var source = '',
1440
- buffer;
1441
- for (var i = 0, len = this.source.length; i < len; i++) {
1442
- var line = this.source[i];
1443
- if (line.appendToBuffer) {
1444
- if (buffer) {
1445
- buffer = buffer + '\n + ' + line.content;
1446
- } else {
1447
- buffer = line.content;
1448
- }
1300
+ return Function.apply(this, params);
1449
1301
  } else {
1450
- if (buffer) {
1451
- source += 'buffer += ' + buffer + ';\n ';
1452
- buffer = undefined;
1453
- }
1454
- source += line + '\n ';
1302
+ var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + this.source.join("\n ") + '}';
1303
+ Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1304
+ return functionSource;
1455
1305
  }
1456
- }
1457
- return source;
1458
- },
1459
-
1460
- // [blockValue]
1461
- //
1462
- // On stack, before: hash, inverse, program, value
1463
- // On stack, after: return value of blockHelperMissing
1464
- //
1465
- // The purpose of this opcode is to take a block of the form
1466
- // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
1467
- // replace it on the stack with the result of properly
1468
- // invoking blockHelperMissing.
1469
- blockValue: function() {
1470
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1471
-
1472
- var params = ["depth0"];
1473
- this.setupParams(0, params);
1474
-
1475
- this.replaceStack(function(current) {
1476
- params.splice(1, 0, current);
1477
- return "blockHelperMissing.call(" + params.join(", ") + ")";
1478
- });
1479
- },
1480
-
1481
- // [ambiguousBlockValue]
1482
- //
1483
- // On stack, before: hash, inverse, program, value
1484
- // Compiler value, before: lastHelper=value of last found helper, if any
1485
- // On stack, after, if no lastHelper: same as [blockValue]
1486
- // On stack, after, if lastHelper: value
1487
- ambiguousBlockValue: function() {
1488
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1489
-
1490
- var params = ["depth0"];
1491
- this.setupParams(0, params);
1306
+ },
1492
1307
 
1493
- var current = this.topStack();
1494
- params.splice(1, 0, current);
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
+ },
1495
1328
 
1496
- // Use the options value generated from the invocation
1497
- params[params.length-1] = 'options';
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';
1498
1337
 
1499
- this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
1500
- },
1338
+ var params = ["depth0"];
1339
+ this.setupParams(0, params);
1501
1340
 
1502
- // [appendContent]
1503
- //
1504
- // On stack, before: ...
1505
- // On stack, after: ...
1506
- //
1507
- // Appends the string value of `content` to the current buffer
1508
- appendContent: function(content) {
1509
- this.source.push(this.appendToBuffer(this.quotedString(content)));
1510
- },
1341
+ var current = this.topStack();
1342
+ params.splice(1, 0, current);
1511
1343
 
1512
- // [append]
1513
- //
1514
- // On stack, before: value, ...
1515
- // On stack, after: ...
1516
- //
1517
- // Coerces `value` to a String and appends it to the current buffer.
1518
- //
1519
- // If `value` is truthy, or 0, it is coerced into a string and appended
1520
- // Otherwise, the empty string is appended
1521
- append: function() {
1522
- // Force anything that is inlined onto the stack so we don't have duplication
1523
- // when we examine local
1524
- this.flushInline();
1525
- var local = this.popStack();
1526
- this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1527
- if (this.environment.isSimple) {
1528
- this.source.push("else { " + this.appendToBuffer("''") + " }");
1529
- }
1530
- },
1344
+ this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
1345
+ },
1531
1346
 
1532
- // [appendEscaped]
1533
- //
1534
- // On stack, before: value, ...
1535
- // On stack, after: ...
1536
- //
1537
- // Escape `value` and append it to the buffer
1538
- appendEscaped: function() {
1539
- this.context.aliases.escapeExpression = 'this.escapeExpression';
1347
+ // [appendContent]
1348
+ //
1349
+ // On stack, before: ...
1350
+ // On stack, after: ...
1351
+ //
1352
+ // Appends the string value of `content` to the current buffer
1353
+ appendContent: function(content) {
1354
+ this.source.push(this.appendToBuffer(this.quotedString(content)));
1355
+ },
1540
1356
 
1541
- this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
1542
- },
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
1366
+ append: function() {
1367
+ var local = this.popStack();
1368
+ this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1369
+ if (this.environment.isSimple) {
1370
+ this.source.push("else { " + this.appendToBuffer("''") + " }");
1371
+ }
1372
+ },
1543
1373
 
1544
- // [getContext]
1545
- //
1546
- // On stack, before: ...
1547
- // On stack, after: ...
1548
- // Compiler value, after: lastContext=depth
1549
- //
1550
- // Set the value of the `lastContext` compiler value to the depth
1551
- getContext: function(depth) {
1552
- if(this.lastContext !== depth) {
1553
- this.lastContext = depth;
1554
- }
1555
- },
1374
+ // [appendEscaped]
1375
+ //
1376
+ // On stack, before: value, ...
1377
+ // On stack, after: ...
1378
+ //
1379
+ // Escape `value` and append it to the buffer
1380
+ appendEscaped: function() {
1381
+ var opcode = this.nextOpcode(), extra = "";
1382
+ this.context.aliases.escapeExpression = 'this.escapeExpression';
1383
+
1384
+ if(opcode && opcode.opcode === 'appendContent') {
1385
+ extra = " + " + this.quotedString(opcode.args[0]);
1386
+ this.eat(opcode);
1387
+ }
1556
1388
 
1557
- // [lookupOnContext]
1558
- //
1559
- // On stack, before: ...
1560
- // On stack, after: currentContext[name], ...
1561
- //
1562
- // Looks up the value of `name` on the current context and pushes
1563
- // it onto the stack.
1564
- lookupOnContext: function(name) {
1565
- this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
1566
- },
1389
+ this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra));
1390
+ },
1567
1391
 
1568
- // [pushContext]
1569
- //
1570
- // On stack, before: ...
1571
- // On stack, after: currentContext, ...
1572
- //
1573
- // Pushes the value of the current context onto the stack.
1574
- pushContext: function() {
1575
- this.pushStackLiteral('depth' + this.lastContext);
1576
- },
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
1399
+ getContext: function(depth) {
1400
+ if(this.lastContext !== depth) {
1401
+ this.lastContext = depth;
1402
+ }
1403
+ },
1577
1404
 
1578
- // [resolvePossibleLambda]
1579
- //
1580
- // On stack, before: value, ...
1581
- // On stack, after: resolved value, ...
1582
- //
1583
- // If the `value` is a lambda, replace it on the stack by
1584
- // the return value of the lambda
1585
- resolvePossibleLambda: function() {
1586
- this.context.aliases.functionType = '"function"';
1587
-
1588
- this.replaceStack(function(current) {
1589
- return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
1590
- });
1591
- },
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
+ },
1592
1415
 
1593
- // [lookup]
1594
- //
1595
- // On stack, before: value, ...
1596
- // On stack, after: value[name], ...
1597
- //
1598
- // Replace the value on the stack with the result of looking
1599
- // up `name` on `value`
1600
- lookup: function(name) {
1601
- this.replaceStack(function(current) {
1602
- return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
1603
- });
1604
- },
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
+ },
1605
1425
 
1606
- // [lookupData]
1607
- //
1608
- // On stack, before: ...
1609
- // On stack, after: data[id], ...
1610
- //
1611
- // Push the result of looking up `id` on the current data
1612
- lookupData: function(id) {
1613
- this.push(this.nameLookup('data', id, 'data'));
1614
- },
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
+ });
1439
+ },
1615
1440
 
1616
- // [pushStringParam]
1617
- //
1618
- // On stack, before: ...
1619
- // On stack, after: string, currentContext, ...
1620
- //
1621
- // This opcode is designed for use in string mode, which
1622
- // provides the string value of a parameter along with its
1623
- // depth rather than resolving it immediately.
1624
- pushStringParam: function(string, type) {
1625
- this.pushStackLiteral('depth' + this.lastContext);
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`
1448
+ lookup: function(name) {
1449
+ this.replaceStack(function(current) {
1450
+ return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
1451
+ });
1452
+ },
1626
1453
 
1627
- this.pushString(type);
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
+ },
1628
1463
 
1629
- if (typeof string === 'string') {
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.
1472
+ pushStringParam: function(string) {
1473
+ this.pushStackLiteral('depth' + this.lastContext);
1630
1474
  this.pushString(string);
1631
- } else {
1632
- this.pushStackLiteral(string);
1633
- }
1634
- },
1635
-
1636
- emptyHash: function() {
1637
- this.pushStackLiteral('{}');
1638
-
1639
- if (this.options.stringParams) {
1640
- this.register('hashTypes', '{}');
1641
- this.register('hashContexts', '{}');
1642
- }
1643
- },
1644
- pushHash: function() {
1645
- this.hash = {values: [], types: [], contexts: []};
1646
- },
1647
- popHash: function() {
1648
- var hash = this.hash;
1649
- this.hash = undefined;
1650
-
1651
- if (this.options.stringParams) {
1652
- this.register('hashContexts', '{' + hash.contexts.join(',') + '}');
1653
- this.register('hashTypes', '{' + hash.types.join(',') + '}');
1654
- }
1655
- this.push('{\n ' + hash.values.join(',\n ') + '\n }');
1656
- },
1657
-
1658
- // [pushString]
1659
- //
1660
- // On stack, before: ...
1661
- // On stack, after: quotedString(string), ...
1662
- //
1663
- // Push a quoted version of `string` onto the stack
1664
- pushString: function(string) {
1665
- this.pushStackLiteral(this.quotedString(string));
1666
- },
1667
-
1668
- // [push]
1669
- //
1670
- // On stack, before: ...
1671
- // On stack, after: expr, ...
1672
- //
1673
- // Push an expression onto the stack
1674
- push: function(expr) {
1675
- this.inlineStack.push(expr);
1676
- return expr;
1677
- },
1475
+ },
1678
1476
 
1679
- // [pushLiteral]
1680
- //
1681
- // On stack, before: ...
1682
- // On stack, after: value, ...
1683
- //
1684
- // Pushes a value onto the stack. This operation prevents
1685
- // the compiler from creating a temporary variable to hold
1686
- // it.
1687
- pushLiteral: function(value) {
1688
- this.pushStackLiteral(value);
1689
- },
1477
+ // [pushString]
1478
+ //
1479
+ // On stack, before: ...
1480
+ // On stack, after: quotedString(string), ...
1481
+ //
1482
+ // Push a quoted version of `string` onto the stack
1483
+ pushString: function(string) {
1484
+ this.pushStackLiteral(this.quotedString(string));
1485
+ },
1690
1486
 
1691
- // [pushProgram]
1692
- //
1693
- // On stack, before: ...
1694
- // On stack, after: program(guid), ...
1695
- //
1696
- // Push a program expression onto the stack. This takes
1697
- // a compile-time guid and converts it into a runtime-accessible
1698
- // expression.
1699
- pushProgram: function(guid) {
1700
- if (guid != null) {
1701
- this.pushStackLiteral(this.programExpression(guid));
1702
- } else {
1703
- this.pushStackLiteral(null);
1704
- }
1705
- },
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
+ },
1706
1496
 
1707
- // [invokeHelper]
1708
- //
1709
- // On stack, before: hash, inverse, program, params..., ...
1710
- // On stack, after: result of helper invocation
1711
- //
1712
- // Pops off the helper's parameters, invokes the helper,
1713
- // and pushes the helper's return value onto the stack.
1714
- //
1715
- // If the helper is not found, `helperMissing` is called.
1716
- invokeHelper: function(paramSize, name) {
1717
- this.context.aliases.helperMissing = 'helpers.helperMissing';
1718
-
1719
- var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
1720
-
1721
- this.push(helper.name);
1722
- this.replaceStack(function(name) {
1723
- return name + ' ? ' + name + '.call(' +
1724
- helper.callParams + ") " + ": helperMissing.call(" +
1725
- helper.helperMissingParams + ")";
1726
- });
1727
- },
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
+ },
1728
1508
 
1729
- // [invokeKnownHelper]
1730
- //
1731
- // On stack, before: hash, inverse, program, params..., ...
1732
- // On stack, after: result of helper invocation
1733
- //
1734
- // This operation is used when the helper is known to exist,
1735
- // so a `helperMissing` fallback is not required.
1736
- invokeKnownHelper: function(paramSize, name) {
1737
- var helper = this.setupHelper(paramSize, name);
1738
- this.push(helper.name + ".call(" + helper.callParams + ")");
1739
- },
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));
1520
+ } else {
1521
+ this.pushStackLiteral(null);
1522
+ }
1523
+ },
1740
1524
 
1741
- // [invokeAmbiguous]
1742
- //
1743
- // On stack, before: hash, inverse, program, params..., ...
1744
- // On stack, after: result of disambiguation
1745
- //
1746
- // This operation is used when an expression like `{{foo}}`
1747
- // is provided, but we don't know at compile-time whether it
1748
- // is a helper or a path.
1749
- //
1750
- // This operation emits more code than the other options,
1751
- // and can be avoided by passing the `knownHelpers` and
1752
- // `knownHelpersOnly` flags at compile-time.
1753
- invokeAmbiguous: function(name, helperCall) {
1754
- this.context.aliases.functionType = '"function"';
1755
-
1756
- this.pushStackLiteral('{}'); // Hash value
1757
- var helper = this.setupHelper(0, name, helperCall);
1758
-
1759
- var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
1760
-
1761
- var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1762
- var nextStack = this.nextStack();
1763
-
1764
- this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
1765
- this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }');
1766
- },
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
+ },
1767
1544
 
1768
- // [invokePartial]
1769
- //
1770
- // On stack, before: context, ...
1771
- // On stack after: result of partial invocation
1772
- //
1773
- // This operation pops off a context, invokes a partial with that context,
1774
- // and pushes the result of the invocation back.
1775
- invokePartial: function(name) {
1776
- var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
1777
-
1778
- if (this.options.data) {
1779
- params.push("data");
1780
- }
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
+ },
1781
1556
 
1782
- this.context.aliases.self = "this";
1783
- this.push("self.invokePartial(" + params.join(", ") + ")");
1784
- },
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');
1579
+ var nextStack = this.nextStack();
1580
+
1581
+ this.source.push('if (foundHelper) { ' + nextStack + ' = foundHelper.call(' + helper.callParams + '); }');
1582
+ this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '() : ' + nextStack + '; }');
1583
+ },
1785
1584
 
1786
- // [assignToHash]
1787
- //
1788
- // On stack, before: value, hash, ...
1789
- // On stack, after: hash, ...
1790
- //
1791
- // Pops a value and hash off the stack, assigns `hash[key] = value`
1792
- // and pushes the hash back onto the stack.
1793
- assignToHash: function(key) {
1794
- var value = this.popStack(),
1795
- context,
1796
- type;
1797
-
1798
- if (this.options.stringParams) {
1799
- type = this.popStack();
1800
- context = this.popStack();
1801
- }
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"];
1594
+
1595
+ if (this.options.data) {
1596
+ params.push("data");
1597
+ }
1802
1598
 
1803
- var hash = this.hash;
1804
- if (context) {
1805
- hash.contexts.push("'" + key + "': " + context);
1806
- }
1807
- if (type) {
1808
- hash.types.push("'" + key + "': " + type);
1809
- }
1810
- hash.values.push("'" + key + "': (" + value + ")");
1811
- },
1599
+ this.context.aliases.self = "this";
1600
+ this.pushStack("self.invokePartial(" + params.join(", ") + ");");
1601
+ },
1812
1602
 
1813
- // HELPERS
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.
1610
+ assignToHash: function(key) {
1611
+ var value = this.popStack();
1612
+ var hash = this.topStack();
1613
+
1614
+ this.source.push(hash + "['" + key + "'] = " + value + ";");
1615
+ },
1814
1616
 
1815
- compiler: JavaScriptCompiler,
1617
+ // HELPERS
1816
1618
 
1817
- compileChildren: function(environment, options) {
1818
- var children = environment.children, child, compiler;
1619
+ compiler: JavaScriptCompiler,
1819
1620
 
1820
- for(var i=0, l=children.length; i<l; i++) {
1821
- child = children[i];
1822
- compiler = new this.compiler();
1621
+ compileChildren: function(environment, options) {
1622
+ var children = environment.children, child, compiler;
1823
1623
 
1824
- var index = this.matchExistingProgram(child);
1624
+ for(var i=0, l=children.length; i<l; i++) {
1625
+ child = children[i];
1626
+ compiler = new this.compiler();
1825
1627
 
1826
- if (index == null) {
1827
1628
  this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
1828
- index = this.context.programs.length;
1629
+ var index = this.context.programs.length;
1829
1630
  child.index = index;
1830
1631
  child.name = 'program' + index;
1831
1632
  this.context.programs[index] = compiler.compile(child, options, this.context);
1832
- this.context.environments[index] = child;
1833
- } else {
1834
- child.index = index;
1835
- child.name = 'program' + index;
1836
- }
1837
- }
1838
- },
1839
- matchExistingProgram: function(child) {
1840
- for (var i = 0, len = this.context.environments.length; i < len; i++) {
1841
- var environment = this.context.environments[i];
1842
- if (environment && environment.equals(child)) {
1843
- return i;
1844
1633
  }
1845
- }
1846
- },
1847
-
1848
- programExpression: function(guid) {
1849
- this.context.aliases.self = "this";
1634
+ },
1850
1635
 
1851
- if(guid == null) {
1852
- return "self.noop";
1853
- }
1636
+ programExpression: function(guid) {
1637
+ this.context.aliases.self = "this";
1854
1638
 
1855
- var child = this.environment.children[guid],
1856
- depths = child.depths.list, depth;
1639
+ if(guid == null) {
1640
+ return "self.noop";
1641
+ }
1857
1642
 
1858
- var programParams = [child.index, child.name, "data"];
1643
+ var child = this.environment.children[guid],
1644
+ depths = child.depths.list, depth;
1859
1645
 
1860
- for(var i=0, l = depths.length; i<l; i++) {
1861
- depth = depths[i];
1646
+ var programParams = [child.index, child.name, "data"];
1862
1647
 
1863
- if(depth === 1) { programParams.push("depth0"); }
1864
- else { programParams.push("depth" + (depth - 1)); }
1865
- }
1648
+ for(var i=0, l = depths.length; i<l; i++) {
1649
+ depth = depths[i];
1866
1650
 
1867
- return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")";
1868
- },
1651
+ if(depth === 1) { programParams.push("depth0"); }
1652
+ else { programParams.push("depth" + (depth - 1)); }
1653
+ }
1869
1654
 
1870
- register: function(name, val) {
1871
- this.useRegister(name);
1872
- this.source.push(name + " = " + val + ";");
1873
- },
1655
+ if(depths.length === 0) {
1656
+ return "self.program(" + programParams.join(", ") + ")";
1657
+ } else {
1658
+ programParams.shift();
1659
+ return "self.programWithDepth(" + programParams.join(", ") + ")";
1660
+ }
1661
+ },
1874
1662
 
1875
- useRegister: function(name) {
1876
- if(!this.registers[name]) {
1877
- this.registers[name] = true;
1878
- this.registers.list.push(name);
1879
- }
1880
- },
1663
+ register: function(name, val) {
1664
+ this.useRegister(name);
1665
+ this.source.push(name + " = " + val + ";");
1666
+ },
1881
1667
 
1882
- pushStackLiteral: function(item) {
1883
- return this.push(new Literal(item));
1884
- },
1668
+ useRegister: function(name) {
1669
+ if(!this.registers[name]) {
1670
+ this.registers[name] = true;
1671
+ this.registers.list.push(name);
1672
+ }
1673
+ },
1885
1674
 
1886
- pushStack: function(item) {
1887
- this.flushInline();
1675
+ pushStackLiteral: function(item) {
1676
+ this.compileStack.push(new Literal(item));
1677
+ return item;
1678
+ },
1888
1679
 
1889
- var stack = this.incrStack();
1890
- if (item) {
1891
- this.source.push(stack + " = " + item + ";");
1892
- }
1893
- this.compileStack.push(stack);
1894
- return stack;
1895
- },
1680
+ pushStack: function(item) {
1681
+ this.source.push(this.incrStack() + " = " + item + ";");
1682
+ this.compileStack.push("stack" + this.stackSlot);
1683
+ return "stack" + this.stackSlot;
1684
+ },
1896
1685
 
1897
- replaceStack: function(callback) {
1898
- var prefix = '',
1899
- inline = this.isInline(),
1900
- stack;
1686
+ replaceStack: function(callback) {
1687
+ var item = callback.call(this, this.topStack());
1901
1688
 
1902
- // If we are currently inline then we want to merge the inline statement into the
1903
- // replacement statement via ','
1904
- if (inline) {
1905
- var top = this.popStack(true);
1689
+ this.source.push(this.topStack() + " = " + item + ";");
1690
+ return "stack" + this.stackSlot;
1691
+ },
1906
1692
 
1907
- if (top instanceof Literal) {
1908
- // Literals do not need to be inlined
1909
- stack = top.value;
1910
- } else {
1911
- // Get or create the current stack name for use by the inline
1912
- var name = this.stackSlot ? this.topStackName() : this.incrStack();
1693
+ nextStack: function(skipCompileStack) {
1694
+ var name = this.incrStack();
1695
+ this.compileStack.push("stack" + this.stackSlot);
1696
+ return name;
1697
+ },
1913
1698
 
1914
- prefix = '(' + this.push(name) + ' = ' + top + '),';
1915
- stack = this.topStack();
1916
- }
1917
- } else {
1918
- stack = this.topStack();
1919
- }
1699
+ incrStack: function() {
1700
+ this.stackSlot++;
1701
+ if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1702
+ return "stack" + this.stackSlot;
1703
+ },
1920
1704
 
1921
- var item = callback.call(this, stack);
1705
+ popStack: function() {
1706
+ var item = this.compileStack.pop();
1922
1707
 
1923
- if (inline) {
1924
- if (this.inlineStack.length || this.compileStack.length) {
1925
- this.popStack();
1926
- }
1927
- this.push('(' + prefix + item + ')');
1928
- } else {
1929
- // Prevent modification of the context depth variable. Through replaceStack
1930
- if (!/^stack/.test(stack)) {
1931
- stack = this.nextStack();
1708
+ if (item instanceof Literal) {
1709
+ return item.value;
1710
+ } else {
1711
+ this.stackSlot--;
1712
+ return item;
1932
1713
  }
1714
+ },
1933
1715
 
1934
- this.source.push(stack + " = (" + prefix + item + ");");
1935
- }
1936
- return stack;
1937
- },
1938
-
1939
- nextStack: function() {
1940
- return this.pushStack();
1941
- },
1716
+ topStack: function() {
1717
+ var item = this.compileStack[this.compileStack.length - 1];
1942
1718
 
1943
- incrStack: function() {
1944
- this.stackSlot++;
1945
- if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1946
- return this.topStackName();
1947
- },
1948
- topStackName: function() {
1949
- return "stack" + this.stackSlot;
1950
- },
1951
- flushInline: function() {
1952
- var inlineStack = this.inlineStack;
1953
- if (inlineStack.length) {
1954
- this.inlineStack = [];
1955
- for (var i = 0, len = inlineStack.length; i < len; i++) {
1956
- var entry = inlineStack[i];
1957
- if (entry instanceof Literal) {
1958
- this.compileStack.push(entry);
1959
- } else {
1960
- this.pushStack(entry);
1961
- }
1719
+ if (item instanceof Literal) {
1720
+ return item.value;
1721
+ } else {
1722
+ return item;
1962
1723
  }
1963
- }
1964
- },
1965
- isInline: function() {
1966
- return this.inlineStack.length;
1967
- },
1724
+ },
1968
1725
 
1969
- popStack: function(wrapped) {
1970
- var inline = this.isInline(),
1971
- item = (inline ? this.inlineStack : this.compileStack).pop();
1726
+ quotedString: function(str) {
1727
+ return '"' + str
1728
+ .replace(/\\/g, '\\\\')
1729
+ .replace(/"/g, '\\"')
1730
+ .replace(/\n/g, '\\n')
1731
+ .replace(/\r/g, '\\r') + '"';
1732
+ },
1972
1733
 
1973
- if (!wrapped && (item instanceof Literal)) {
1974
- return item.value;
1975
- } else {
1976
- if (!inline) {
1977
- this.stackSlot--;
1978
- }
1979
- return item;
1980
- }
1981
- },
1734
+ setupHelper: function(paramSize, name) {
1735
+ var params = [];
1736
+ this.setupParams(paramSize, params);
1737
+ var foundHelper = this.nameLookup('helpers', name, 'helper');
1982
1738
 
1983
- topStack: function(wrapped) {
1984
- var stack = (this.isInline() ? this.inlineStack : this.compileStack),
1985
- item = stack[stack.length - 1];
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
+ },
1986
1746
 
1987
- if (!wrapped && (item instanceof Literal)) {
1988
- return item.value;
1989
- } else {
1990
- return item;
1991
- }
1992
- },
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;
1993
1751
 
1994
- quotedString: function(str) {
1995
- return '"' + str
1996
- .replace(/\\/g, '\\\\')
1997
- .replace(/"/g, '\\"')
1998
- .replace(/\n/g, '\\n')
1999
- .replace(/\r/g, '\\r')
2000
- .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
2001
- .replace(/\u2029/g, '\\u2029') + '"';
2002
- },
1752
+ options.push("hash:" + this.popStack());
2003
1753
 
2004
- setupHelper: function(paramSize, name, missingParams) {
2005
- var params = [];
2006
- this.setupParams(paramSize, params, missingParams);
2007
- var foundHelper = this.nameLookup('helpers', name, 'helper');
1754
+ inverse = this.popStack();
1755
+ program = this.popStack();
2008
1756
 
2009
- return {
2010
- params: params,
2011
- name: foundHelper,
2012
- callParams: ["depth0"].concat(params).join(", "),
2013
- helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
2014
- };
2015
- },
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
+ }
2016
1764
 
2017
- // the params and contexts arguments are passed in arrays
2018
- // to fill in
2019
- setupParams: function(paramSize, params, useRegister) {
2020
- var options = [], contexts = [], types = [], param, inverse, program;
1765
+ if (!inverse) {
1766
+ this.context.aliases.self = "this";
1767
+ inverse = "self.noop";
1768
+ }
2021
1769
 
2022
- options.push("hash:" + this.popStack());
1770
+ options.push("inverse:" + inverse);
1771
+ options.push("fn:" + program);
1772
+ }
2023
1773
 
2024
- inverse = this.popStack();
2025
- program = this.popStack();
1774
+ for(var i=0; i<paramSize; i++) {
1775
+ param = this.popStack();
1776
+ params.push(param);
2026
1777
 
2027
- // Avoid setting fn and inverse if neither are set. This allows
2028
- // helpers to do a check for `if (options.fn)`
2029
- if (program || inverse) {
2030
- if (!program) {
2031
- this.context.aliases.self = "this";
2032
- program = "self.noop";
1778
+ if(this.options.stringParams) {
1779
+ contexts.push(this.popStack());
1780
+ }
2033
1781
  }
2034
1782
 
2035
- if (!inverse) {
2036
- this.context.aliases.self = "this";
2037
- inverse = "self.noop";
1783
+ if (this.options.stringParams) {
1784
+ options.push("contexts:[" + contexts.join(",") + "]");
2038
1785
  }
2039
1786
 
2040
- options.push("inverse:" + inverse);
2041
- options.push("fn:" + program);
2042
- }
2043
-
2044
- for(var i=0; i<paramSize; i++) {
2045
- param = this.popStack();
2046
- params.push(param);
2047
-
2048
- if(this.options.stringParams) {
2049
- types.push(this.popStack());
2050
- contexts.push(this.popStack());
1787
+ if(this.options.data) {
1788
+ options.push("data:data");
2051
1789
  }
2052
- }
2053
1790
 
2054
- if (this.options.stringParams) {
2055
- options.push("contexts:[" + contexts.join(",") + "]");
2056
- options.push("types:[" + types.join(",") + "]");
2057
- options.push("hashContexts:hashContexts");
2058
- options.push("hashTypes:hashTypes");
2059
- }
2060
-
2061
- if(this.options.data) {
2062
- options.push("data:data");
1791
+ params.push("{" + options.join(",") + "}");
1792
+ return params.join(", ");
2063
1793
  }
1794
+ };
2064
1795
 
2065
- options = "{" + options.join(",") + "}";
2066
- if (useRegister) {
2067
- this.register('options', options);
2068
- params.push('options');
2069
- } else {
2070
- params.push(options);
2071
- }
2072
- return params.join(", ");
1796
+ var reservedWords = (
1797
+ "break else new var" +
1798
+ " case finally return void" +
1799
+ " catch for switch while" +
1800
+ " continue function this with" +
1801
+ " default if throw" +
1802
+ " delete in try" +
1803
+ " do instanceof typeof" +
1804
+ " abstract enum int short" +
1805
+ " boolean export interface static" +
1806
+ " byte extends long super" +
1807
+ " char final native synchronized" +
1808
+ " class float package throws" +
1809
+ " const goto private transient" +
1810
+ " debugger implements protected volatile" +
1811
+ " double import public let yield"
1812
+ ).split(" ");
1813
+
1814
+ var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
1815
+
1816
+ for(var i=0, l=reservedWords.length; i<l; i++) {
1817
+ compilerWords[reservedWords[i]] = true;
2073
1818
  }
2074
- };
2075
1819
 
2076
- var reservedWords = (
2077
- "break else new var" +
2078
- " case finally return void" +
2079
- " catch for switch while" +
2080
- " continue function this with" +
2081
- " default if throw" +
2082
- " delete in try" +
2083
- " do instanceof typeof" +
2084
- " abstract enum int short" +
2085
- " boolean export interface static" +
2086
- " byte extends long super" +
2087
- " char final native synchronized" +
2088
- " class float package throws" +
2089
- " const goto private transient" +
2090
- " debugger implements protected volatile" +
2091
- " double import public let yield"
2092
- ).split(" ");
2093
-
2094
- var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
2095
-
2096
- for(var i=0, l=reservedWords.length; i<l; i++) {
2097
- compilerWords[reservedWords[i]] = true;
2098
- }
2099
-
2100
- JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
2101
- if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
2102
- return true;
2103
- }
2104
- return false;
2105
- };
1820
+ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
1821
+ if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
1822
+ return true;
1823
+ }
1824
+ return false;
1825
+ };
2106
1826
 
2107
- Handlebars.precompile = function(input, options) {
2108
- if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2109
- throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
2110
- }
1827
+ })(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
2111
1828
 
1829
+ Handlebars.precompile = function(string, options) {
2112
1830
  options = options || {};
2113
- if (!('data' in options)) {
2114
- options.data = true;
2115
- }
2116
- var ast = Handlebars.parse(input);
2117
- var environment = new Compiler().compile(ast, options);
2118
- return new JavaScriptCompiler().compile(environment, options);
2119
- };
2120
1831
 
2121
- Handlebars.compile = function(input, options) {
2122
- if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2123
- throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
2124
- }
1832
+ var ast = Handlebars.parse(string);
1833
+ var environment = new Handlebars.Compiler().compile(ast, options);
1834
+ return new Handlebars.JavaScriptCompiler().compile(environment, options);
1835
+ };
2125
1836
 
1837
+ Handlebars.compile = function(string, options) {
2126
1838
  options = options || {};
2127
- if (!('data' in options)) {
2128
- options.data = true;
2129
- }
1839
+
2130
1840
  var compiled;
2131
1841
  function compile() {
2132
- var ast = Handlebars.parse(input);
2133
- var environment = new Compiler().compile(ast, options);
2134
- var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true);
1842
+ var ast = Handlebars.parse(string);
1843
+ var environment = new Handlebars.Compiler().compile(ast, options);
1844
+ var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
2135
1845
  return Handlebars.template(templateSpec);
2136
1846
  }
2137
1847
 
@@ -2143,10 +1853,8 @@ Handlebars.compile = function(input, options) {
2143
1853
  return compiled.call(this, context, options);
2144
1854
  };
2145
1855
  };
2146
-
2147
1856
  ;
2148
1857
  // lib/handlebars/runtime.js
2149
-
2150
1858
  Handlebars.VM = {
2151
1859
  template: function(templateSpec) {
2152
1860
  // Just add water
@@ -2157,63 +1865,39 @@ Handlebars.VM = {
2157
1865
  program: function(i, fn, data) {
2158
1866
  var programWrapper = this.programs[i];
2159
1867
  if(data) {
2160
- programWrapper = Handlebars.VM.program(i, fn, data);
2161
- } else if (!programWrapper) {
2162
- programWrapper = this.programs[i] = Handlebars.VM.program(i, fn);
1868
+ return Handlebars.VM.program(fn, data);
1869
+ } else if(programWrapper) {
1870
+ return programWrapper;
1871
+ } else {
1872
+ programWrapper = this.programs[i] = Handlebars.VM.program(fn);
1873
+ return programWrapper;
2163
1874
  }
2164
- return programWrapper;
2165
1875
  },
2166
1876
  programWithDepth: Handlebars.VM.programWithDepth,
2167
- noop: Handlebars.VM.noop,
2168
- compilerInfo: null
1877
+ noop: Handlebars.VM.noop
2169
1878
  };
2170
1879
 
2171
1880
  return function(context, options) {
2172
1881
  options = options || {};
2173
- var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
2174
-
2175
- var compilerInfo = container.compilerInfo || [],
2176
- compilerRevision = compilerInfo[0] || 1,
2177
- currentRevision = Handlebars.COMPILER_REVISION;
2178
-
2179
- if (compilerRevision !== currentRevision) {
2180
- if (compilerRevision < currentRevision) {
2181
- var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision],
2182
- compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision];
2183
- throw "Template was precompiled with an older version of Handlebars than the current runtime. "+
2184
- "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").";
2185
- } else {
2186
- // Use the embedded version info since the runtime doesn't know about this revision yet
2187
- throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+
2188
- "Please update your runtime to a newer version ("+compilerInfo[1]+").";
2189
- }
2190
- }
2191
-
2192
- return result;
1882
+ return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
2193
1883
  };
2194
1884
  },
2195
1885
 
2196
- programWithDepth: function(i, fn, data /*, $depth */) {
2197
- var args = Array.prototype.slice.call(arguments, 3);
1886
+ programWithDepth: function(fn, data, $depth) {
1887
+ var args = Array.prototype.slice.call(arguments, 2);
2198
1888
 
2199
- var program = function(context, options) {
1889
+ return function(context, options) {
2200
1890
  options = options || {};
2201
1891
 
2202
1892
  return fn.apply(this, [context, options.data || data].concat(args));
2203
1893
  };
2204
- program.program = i;
2205
- program.depth = args.length;
2206
- return program;
2207
1894
  },
2208
- program: function(i, fn, data) {
2209
- var program = function(context, options) {
1895
+ program: function(fn, data) {
1896
+ return function(context, options) {
2210
1897
  options = options || {};
2211
1898
 
2212
1899
  return fn(context, options.data || data);
2213
1900
  };
2214
- program.program = i;
2215
- program.depth = 0;
2216
- return program;
2217
1901
  },
2218
1902
  noop: function() { return ""; },
2219
1903
  invokePartial: function(partial, name, context, helpers, partials, data) {
@@ -2234,6 +1918,3 @@ Handlebars.VM = {
2234
1918
 
2235
1919
  Handlebars.template = Handlebars.VM.template;
2236
1920
  ;
2237
- // lib/handlebars/browser-suffix.js
2238
- })(Handlebars);
2239
- ;