rasputin 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -49,6 +49,11 @@ In your stylesheet asset manifest (app/assets/stylesheets/application.css) add t
49
49
  ChangeLog
50
50
  ----------
51
51
 
52
+ 0.8.2
53
+
54
+ * rails 3.1 support
55
+ * fix sproutcore-touch
56
+
52
57
  0.8.1
53
58
 
54
59
  * add normalize.css
data/lib/rasputin.rb CHANGED
@@ -1,7 +1,19 @@
1
+ require 'tilt'
2
+ require 'sprockets/engines'
3
+
1
4
  require "rasputin/version"
2
- require "rasputin/handlebars_template"
5
+ require "rasputin/handlebars/compiler"
6
+ require "rasputin/handlebars/template"
7
+
8
+ require "rasputin/slim" if defined? Slim
3
9
 
4
10
  module Rasputin
5
11
  class Engine < ::Rails::Engine
12
+ config.rasputin = ActiveSupport::OrderedOptions.new
13
+ config.rasputin.precompile_handlebars = true
14
+
15
+ initializer :setup_rasputin do |app|
16
+ app.assets.register_engine '.handlebars', Rasputin::HandlebarsTemplate
17
+ end
6
18
  end
7
19
  end
@@ -0,0 +1,44 @@
1
+ require "execjs"
2
+
3
+ module Rasputin
4
+ module Handlebars
5
+ module Source
6
+
7
+ def self.bundled_path
8
+ File.expand_path("../handlebars.js", __FILE__)
9
+ end
10
+
11
+ def self.path
12
+ @path ||= ENV["HANDLEBARS_SOURCE_PATH"] || bundled_path
13
+ end
14
+
15
+ def self.path=(path)
16
+ @contents = @version = @context = nil
17
+ @path = path
18
+ end
19
+
20
+ def self.contents
21
+ @contents ||= File.read(path)
22
+ end
23
+
24
+ def self.version
25
+ @version ||= contents[/^Handlebars.VERSION = "([^"]*)"/, 1]
26
+ end
27
+
28
+ def self.context
29
+ @context ||= ExecJS.compile(contents)
30
+ end
31
+ end
32
+
33
+ class << self
34
+ def version
35
+ Source.version
36
+ end
37
+
38
+ def compile(template)
39
+ template = template.read if template.respond_to?(:read)
40
+ Source.context.call("SC.Handlebars.precompile", template)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,1617 @@
1
+
2
+ var Handlebars = {};
3
+ this.Handlebars = Handlebars;
4
+
5
+ Handlebars.VERSION = "1.0.beta.2";
6
+
7
+ Handlebars.helpers = {};
8
+ Handlebars.partials = {};
9
+
10
+ Handlebars.registerHelper = function(name, fn, inverse) {
11
+ if(inverse) { fn.not = inverse; }
12
+ this.helpers[name] = fn;
13
+ };
14
+
15
+ Handlebars.registerPartial = function(name, str) {
16
+ this.partials[name] = str;
17
+ };
18
+
19
+ Handlebars.registerHelper('helperMissing', function(arg) {
20
+ if(arguments.length === 2) {
21
+ return undefined;
22
+ } else {
23
+ throw new Error("Could not find property '" + arg + "'");
24
+ }
25
+ });
26
+
27
+ Handlebars.registerHelper('blockHelperMissing', function(context, options) {
28
+ var inverse = options.inverse || function() {}, fn = options.fn;
29
+
30
+
31
+ var ret = "";
32
+ var type = Object.prototype.toString.call(context);
33
+
34
+ if(type === "[object Function]") {
35
+ context = context();
36
+ }
37
+
38
+ if(context === true) {
39
+ return fn(this);
40
+ } else if(context === false || context == null) {
41
+ return inverse(this);
42
+ } else if(type === "[object Array]") {
43
+ if(context.length > 0) {
44
+ for(var i=0, j=context.length; i<j; i++) {
45
+ ret = ret + fn(context[i]);
46
+ }
47
+ } else {
48
+ ret = inverse(this);
49
+ }
50
+ return ret;
51
+ } else {
52
+ return fn(context);
53
+ }
54
+ });
55
+
56
+ Handlebars.registerHelper('each', function(context, options) {
57
+ var fn = options.fn, inverse = options.inverse;
58
+ var ret = "";
59
+
60
+ if(context && context.length > 0) {
61
+ for(var i=0, j=context.length; i<j; i++) {
62
+ ret = ret + fn(context[i]);
63
+ }
64
+ } else {
65
+ ret = inverse(this);
66
+ }
67
+ return ret;
68
+ });
69
+
70
+ Handlebars.registerHelper('if', function(context, options) {
71
+ if(!context || Handlebars.Utils.isEmpty(context)) {
72
+ return options.inverse(this);
73
+ } else {
74
+ return options.fn(this);
75
+ }
76
+ });
77
+
78
+ Handlebars.registerHelper('unless', function(context, options) {
79
+ var fn = options.fn, inverse = options.inverse;
80
+ options.fn = inverse;
81
+ options.inverse = fn;
82
+
83
+ return Handlebars.helpers['if'].call(this, context, options);
84
+ });
85
+
86
+ Handlebars.registerHelper('with', function(context, options) {
87
+ return options.fn(context);
88
+ });
89
+ ;
90
+ // lib/handlebars/compiler/parser.js
91
+ /* Jison generated parser */
92
+ var handlebars = (function(){
93
+ var parser = {trace: function trace() { },
94
+ yy: {},
95
+ 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,"param":27,"STRING":28,"INTEGER":29,"BOOLEAN":30,"hashSegments":31,"hashSegment":32,"ID":33,"EQUALS":34,"pathSegments":35,"SEP":36,"$accept":0,"$end":1},
96
+ 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:"STRING",29:"INTEGER",30:"BOOLEAN",33:"ID",34:"EQUALS",36:"SEP"},
97
+ productions_: [0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[25,2],[25,1],[27,1],[27,1],[27,1],[27,1],[26,1],[31,2],[31,1],[32,3],[32,3],[32,3],[32,3],[21,1],[35,3],[35,1]],
98
+ performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
99
+
100
+ var $0 = $$.length - 1;
101
+ switch (yystate) {
102
+ case 1: return $$[$0-1]
103
+ break;
104
+ case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0])
105
+ break;
106
+ case 3: this.$ = new yy.ProgramNode($$[$0])
107
+ break;
108
+ case 4: this.$ = new yy.ProgramNode([])
109
+ break;
110
+ case 5: this.$ = [$$[$0]]
111
+ break;
112
+ case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]
113
+ break;
114
+ case 7: this.$ = new yy.InverseNode($$[$0-2], $$[$0-1], $$[$0])
115
+ break;
116
+ case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0])
117
+ break;
118
+ case 9: this.$ = $$[$0]
119
+ break;
120
+ case 10: this.$ = $$[$0]
121
+ break;
122
+ case 11: this.$ = new yy.ContentNode($$[$0])
123
+ break;
124
+ case 12: this.$ = new yy.CommentNode($$[$0])
125
+ break;
126
+ case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
127
+ break;
128
+ case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
129
+ break;
130
+ case 15: this.$ = $$[$0-1]
131
+ break;
132
+ case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
133
+ break;
134
+ case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true)
135
+ break;
136
+ case 18: this.$ = new yy.PartialNode($$[$0-1])
137
+ break;
138
+ case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1])
139
+ break;
140
+ case 20:
141
+ break;
142
+ case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]]
143
+ break;
144
+ case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null]
145
+ break;
146
+ case 23: this.$ = [[$$[$0-1]], $$[$0]]
147
+ break;
148
+ case 24: this.$ = [[$$[$0]], null]
149
+ break;
150
+ case 25: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
151
+ break;
152
+ case 26: this.$ = [$$[$0]]
153
+ break;
154
+ case 27: this.$ = $$[$0]
155
+ break;
156
+ case 28: this.$ = new yy.StringNode($$[$0])
157
+ break;
158
+ case 29: this.$ = new yy.IntegerNode($$[$0])
159
+ break;
160
+ case 30: this.$ = new yy.BooleanNode($$[$0])
161
+ break;
162
+ case 31: this.$ = new yy.HashNode($$[$0])
163
+ break;
164
+ case 32: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]
165
+ break;
166
+ case 33: this.$ = [$$[$0]]
167
+ break;
168
+ case 34: this.$ = [$$[$0-2], $$[$0]]
169
+ break;
170
+ case 35: this.$ = [$$[$0-2], new yy.StringNode($$[$0])]
171
+ break;
172
+ case 36: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])]
173
+ break;
174
+ case 37: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])]
175
+ break;
176
+ case 38: this.$ = new yy.IdNode($$[$0])
177
+ break;
178
+ case 39: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
179
+ break;
180
+ case 40: this.$ = [$$[$0]]
181
+ break;
182
+ }
183
+ },
184
+ 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,33:[1,25],35:24},{17:26,21:23,33:[1,25],35:24},{17:27,21:23,33:[1,25],35:24},{17:28,21:23,33:[1,25],35:24},{21:29,33:[1,25],35:24},{1:[2,1]},{6:30,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,31],21:23,33:[1,25],35:24},{10:32,20:[1,33]},{10:34,20:[1,33]},{18:[1,35]},{18:[2,24],21:40,25:36,26:37,27:38,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,38],28:[2,38],29:[2,38],30:[2,38],33:[2,38],36:[1,46]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],36:[2,40]},{18:[1,47]},{18:[1,48]},{18:[1,49]},{18:[1,50],21:51,33:[1,25],35:24},{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:52,33:[1,25],35:24},{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:40,26:53,27:54,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,23]},{18:[2,26],28:[2,26],29:[2,26],30:[2,26],33:[2,26]},{18:[2,31],32:55,33:[1,56]},{18:[2,27],28:[2,27],29:[2,27],30:[2,27],33:[2,27]},{18:[2,28],28:[2,28],29:[2,28],30:[2,28],33:[2,28]},{18:[2,29],28:[2,29],29:[2,29],30:[2,29],33:[2,29]},{18:[2,30],28:[2,30],29:[2,30],30:[2,30],33:[2,30]},{18:[2,33],33:[2,33]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],34:[1,57],36:[2,40]},{33:[1,58]},{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,59]},{18:[1,60]},{18:[2,21]},{18:[2,25],28:[2,25],29:[2,25],30:[2,25],33:[2,25]},{18:[2,32],33:[2,32]},{34:[1,57]},{21:61,28:[1,62],29:[1,63],30:[1,64],33:[1,25],35:24},{18:[2,39],28:[2,39],29:[2,39],30:[2,39],33:[2,39],36:[2,39]},{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,34],33:[2,34]},{18:[2,35],33:[2,35]},{18:[2,36],33:[2,36]},{18:[2,37],33:[2,37]}],
185
+ defaultActions: {16:[2,1],37:[2,23],53:[2,21]},
186
+ parseError: function parseError(str, hash) {
187
+ throw new Error(str);
188
+ },
189
+ parse: function parse(input) {
190
+ var self = this,
191
+ stack = [0],
192
+ vstack = [null], // semantic value stack
193
+ lstack = [], // location stack
194
+ table = this.table,
195
+ yytext = '',
196
+ yylineno = 0,
197
+ yyleng = 0,
198
+ recovering = 0,
199
+ TERROR = 2,
200
+ EOF = 1;
201
+
202
+ //this.reductionCount = this.shiftCount = 0;
203
+
204
+ this.lexer.setInput(input);
205
+ this.lexer.yy = this.yy;
206
+ this.yy.lexer = this.lexer;
207
+ if (typeof this.lexer.yylloc == 'undefined')
208
+ this.lexer.yylloc = {};
209
+ var yyloc = this.lexer.yylloc;
210
+ lstack.push(yyloc);
211
+
212
+ if (typeof this.yy.parseError === 'function')
213
+ this.parseError = this.yy.parseError;
214
+
215
+ function popStack (n) {
216
+ stack.length = stack.length - 2*n;
217
+ vstack.length = vstack.length - n;
218
+ lstack.length = lstack.length - n;
219
+ }
220
+
221
+ function lex() {
222
+ var token;
223
+ token = self.lexer.lex() || 1; // $end = 1
224
+ // if token isn't its numeric value, convert
225
+ if (typeof token !== 'number') {
226
+ token = self.symbols_[token] || token;
227
+ }
228
+ return token;
229
+ };
230
+
231
+ var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
232
+ while (true) {
233
+ // retreive state number from top of stack
234
+ state = stack[stack.length-1];
235
+
236
+ // use default actions if available
237
+ if (this.defaultActions[state]) {
238
+ action = this.defaultActions[state];
239
+ } else {
240
+ if (symbol == null)
241
+ symbol = lex();
242
+ // read action for current state and first input
243
+ action = table[state] && table[state][symbol];
244
+ }
245
+
246
+ // handle parse error
247
+ if (typeof action === 'undefined' || !action.length || !action[0]) {
248
+
249
+ if (!recovering) {
250
+ // Report error
251
+ expected = [];
252
+ for (p in table[state]) if (this.terminals_[p] && p > 2) {
253
+ expected.push("'"+this.terminals_[p]+"'");
254
+ }
255
+ var errStr = '';
256
+ if (this.lexer.showPosition) {
257
+ errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', ');
258
+ } else {
259
+ errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
260
+ (symbol == 1 /*EOF*/ ? "end of input" :
261
+ ("'"+(this.terminals_[symbol] || symbol)+"'"));
262
+ }
263
+ this.parseError(errStr,
264
+ {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
265
+ }
266
+
267
+ // just recovered from another error
268
+ if (recovering == 3) {
269
+ if (symbol == EOF) {
270
+ throw new Error(errStr || 'Parsing halted.');
271
+ }
272
+
273
+ // discard current lookahead and grab another
274
+ yyleng = this.lexer.yyleng;
275
+ yytext = this.lexer.yytext;
276
+ yylineno = this.lexer.yylineno;
277
+ yyloc = this.lexer.yylloc;
278
+ symbol = lex();
279
+ }
280
+
281
+ // try to recover from error
282
+ while (1) {
283
+ // check for error recovery rule in this state
284
+ if ((TERROR.toString()) in table[state]) {
285
+ break;
286
+ }
287
+ if (state == 0) {
288
+ throw new Error(errStr || 'Parsing halted.');
289
+ }
290
+ popStack(1);
291
+ state = stack[stack.length-1];
292
+ }
293
+
294
+ preErrorSymbol = symbol; // save the lookahead token
295
+ symbol = TERROR; // insert generic error symbol as new lookahead
296
+ state = stack[stack.length-1];
297
+ action = table[state] && table[state][TERROR];
298
+ recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
299
+ }
300
+
301
+ // this shouldn't happen, unless resolve defaults are off
302
+ if (action[0] instanceof Array && action.length > 1) {
303
+ throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
304
+ }
305
+
306
+ switch (action[0]) {
307
+
308
+ case 1: // shift
309
+ //this.shiftCount++;
310
+
311
+ stack.push(symbol);
312
+ vstack.push(this.lexer.yytext);
313
+ lstack.push(this.lexer.yylloc);
314
+ stack.push(action[1]); // push state
315
+ symbol = null;
316
+ if (!preErrorSymbol) { // normal execution/no error
317
+ yyleng = this.lexer.yyleng;
318
+ yytext = this.lexer.yytext;
319
+ yylineno = this.lexer.yylineno;
320
+ yyloc = this.lexer.yylloc;
321
+ if (recovering > 0)
322
+ recovering--;
323
+ } else { // error just occurred, resume old lookahead f/ before error
324
+ symbol = preErrorSymbol;
325
+ preErrorSymbol = null;
326
+ }
327
+ break;
328
+
329
+ case 2: // reduce
330
+ //this.reductionCount++;
331
+
332
+ len = this.productions_[action[1]][1];
333
+
334
+ // perform semantic action
335
+ yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
336
+ // default location, uses first token for firsts, last for lasts
337
+ yyval._$ = {
338
+ first_line: lstack[lstack.length-(len||1)].first_line,
339
+ last_line: lstack[lstack.length-1].last_line,
340
+ first_column: lstack[lstack.length-(len||1)].first_column,
341
+ last_column: lstack[lstack.length-1].last_column
342
+ };
343
+ r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
344
+
345
+ if (typeof r !== 'undefined') {
346
+ return r;
347
+ }
348
+
349
+ // pop off stack
350
+ if (len) {
351
+ stack = stack.slice(0,-1*len*2);
352
+ vstack = vstack.slice(0, -1*len);
353
+ lstack = lstack.slice(0, -1*len);
354
+ }
355
+
356
+ stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
357
+ vstack.push(yyval.$);
358
+ lstack.push(yyval._$);
359
+ // goto new state = table[STATE][NONTERMINAL]
360
+ newState = table[stack[stack.length-2]][stack[stack.length-1]];
361
+ stack.push(newState);
362
+ break;
363
+
364
+ case 3: // accept
365
+ return true;
366
+ }
367
+
368
+ }
369
+
370
+ return true;
371
+ }};/* Jison generated lexer */
372
+ var lexer = (function(){var lexer = ({EOF:1,
373
+ parseError:function parseError(str, hash) {
374
+ if (this.yy.parseError) {
375
+ this.yy.parseError(str, hash);
376
+ } else {
377
+ throw new Error(str);
378
+ }
379
+ },
380
+ setInput:function (input) {
381
+ this._input = input;
382
+ this._more = this._less = this.done = false;
383
+ this.yylineno = this.yyleng = 0;
384
+ this.yytext = this.matched = this.match = '';
385
+ this.conditionStack = ['INITIAL'];
386
+ this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
387
+ return this;
388
+ },
389
+ input:function () {
390
+ var ch = this._input[0];
391
+ this.yytext+=ch;
392
+ this.yyleng++;
393
+ this.match+=ch;
394
+ this.matched+=ch;
395
+ var lines = ch.match(/\n/);
396
+ if (lines) this.yylineno++;
397
+ this._input = this._input.slice(1);
398
+ return ch;
399
+ },
400
+ unput:function (ch) {
401
+ this._input = ch + this._input;
402
+ return this;
403
+ },
404
+ more:function () {
405
+ this._more = true;
406
+ return this;
407
+ },
408
+ pastInput:function () {
409
+ var past = this.matched.substr(0, this.matched.length - this.match.length);
410
+ return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
411
+ },
412
+ upcomingInput:function () {
413
+ var next = this.match;
414
+ if (next.length < 20) {
415
+ next += this._input.substr(0, 20-next.length);
416
+ }
417
+ return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
418
+ },
419
+ showPosition:function () {
420
+ var pre = this.pastInput();
421
+ var c = new Array(pre.length + 1).join("-");
422
+ return pre + this.upcomingInput() + "\n" + c+"^";
423
+ },
424
+ next:function () {
425
+ if (this.done) {
426
+ return this.EOF;
427
+ }
428
+ if (!this._input) this.done = true;
429
+
430
+ var token,
431
+ match,
432
+ col,
433
+ lines;
434
+ if (!this._more) {
435
+ this.yytext = '';
436
+ this.match = '';
437
+ }
438
+ var rules = this._currentRules();
439
+ for (var i=0;i < rules.length; i++) {
440
+ match = this._input.match(this.rules[rules[i]]);
441
+ if (match) {
442
+ lines = match[0].match(/\n.*/g);
443
+ if (lines) this.yylineno += lines.length;
444
+ this.yylloc = {first_line: this.yylloc.last_line,
445
+ last_line: this.yylineno+1,
446
+ first_column: this.yylloc.last_column,
447
+ last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
448
+ this.yytext += match[0];
449
+ this.match += match[0];
450
+ this.matches = match;
451
+ this.yyleng = this.yytext.length;
452
+ this._more = false;
453
+ this._input = this._input.slice(match[0].length);
454
+ this.matched += match[0];
455
+ token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);
456
+ if (token) return token;
457
+ else return;
458
+ }
459
+ }
460
+ if (this._input === "") {
461
+ return this.EOF;
462
+ } else {
463
+ this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
464
+ {text: "", token: null, line: this.yylineno});
465
+ }
466
+ },
467
+ lex:function lex() {
468
+ var r = this.next();
469
+ if (typeof r !== 'undefined') {
470
+ return r;
471
+ } else {
472
+ return this.lex();
473
+ }
474
+ },
475
+ begin:function begin(condition) {
476
+ this.conditionStack.push(condition);
477
+ },
478
+ popState:function popState() {
479
+ return this.conditionStack.pop();
480
+ },
481
+ _currentRules:function _currentRules() {
482
+ return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
483
+ }});
484
+ lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
485
+
486
+ var YYSTATE=YY_START
487
+ switch($avoiding_name_collisions) {
488
+ case 0: this.begin("mu"); if (yy_.yytext) return 14;
489
+ break;
490
+ case 1: return 14;
491
+ break;
492
+ case 2: return 24;
493
+ break;
494
+ case 3: return 16;
495
+ break;
496
+ case 4: return 20;
497
+ break;
498
+ case 5: return 19;
499
+ break;
500
+ case 6: return 19;
501
+ break;
502
+ case 7: return 23;
503
+ break;
504
+ case 8: return 23;
505
+ break;
506
+ case 9: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.begin("INITIAL"); return 15;
507
+ break;
508
+ case 10: return 22;
509
+ break;
510
+ case 11: return 34;
511
+ break;
512
+ case 12: return 33;
513
+ break;
514
+ case 13: return 33;
515
+ break;
516
+ case 14: return 36;
517
+ break;
518
+ case 15: /*ignore whitespace*/
519
+ break;
520
+ case 16: this.begin("INITIAL"); return 18;
521
+ break;
522
+ case 17: this.begin("INITIAL"); return 18;
523
+ break;
524
+ case 18: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 28;
525
+ break;
526
+ case 19: return 30;
527
+ break;
528
+ case 20: return 30;
529
+ break;
530
+ case 21: return 29;
531
+ break;
532
+ case 22: return 33;
533
+ break;
534
+ case 23: return 'INVALID';
535
+ break;
536
+ case 24: return 5;
537
+ break;
538
+ }
539
+ };
540
+ lexer.rules = [/^[^\x00]*?(?=(\{\{))/,/^[^\x00]+/,/^\{\{>/,/^\{\{#/,/^\{\{\//,/^\{\{\^/,/^\{\{\s*else\b/,/^\{\{\{/,/^\{\{&/,/^\{\{![\s\S]*?\}\}/,/^\{\{/,/^=/,/^\.(?=[} ])/,/^\.\./,/^[/.]/,/^\s+/,/^\}\}\}/,/^\}\}/,/^"(\\["]|[^"])*"/,/^true(?=[}\s])/,/^false(?=[}\s])/,/^[0-9]+(?=[}\s])/,/^[a-zA-Z0-9_$-]+(?=[=}\s/.])/,/^./,/^$/];
541
+ lexer.conditions = {"mu":{"rules":[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24],"inclusive":false},"INITIAL":{"rules":[0,1,24],"inclusive":true}};return lexer;})()
542
+ parser.lexer = lexer;
543
+ return parser;
544
+ })();
545
+
546
+ // lib/handlebars/compiler/base.js
547
+ Handlebars.Parser = handlebars;
548
+
549
+ Handlebars.parse = function(string) {
550
+ Handlebars.Parser.yy = Handlebars.AST;
551
+ return Handlebars.Parser.parse(string);
552
+ };
553
+
554
+ Handlebars.print = function(ast) {
555
+ return new Handlebars.PrintVisitor().accept(ast);
556
+ };
557
+
558
+ Handlebars.logger = {
559
+ DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
560
+
561
+ // override in the host environment
562
+ log: function(level, str) {}
563
+ };
564
+
565
+ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
566
+ ;
567
+ // lib/handlebars/compiler/ast.js
568
+ (function() {
569
+
570
+ Handlebars.AST = {};
571
+
572
+ Handlebars.AST.ProgramNode = function(statements, inverse) {
573
+ this.type = "program";
574
+ this.statements = statements;
575
+ if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
576
+ };
577
+
578
+ Handlebars.AST.MustacheNode = function(params, hash, unescaped) {
579
+ this.type = "mustache";
580
+ this.id = params[0];
581
+ this.params = params.slice(1);
582
+ this.hash = hash;
583
+ this.escaped = !unescaped;
584
+ };
585
+
586
+ Handlebars.AST.PartialNode = function(id, context) {
587
+ this.type = "partial";
588
+
589
+ // TODO: disallow complex IDs
590
+
591
+ this.id = id;
592
+ this.context = context;
593
+ };
594
+
595
+ var verifyMatch = function(open, close) {
596
+ if(open.original !== close.original) {
597
+ throw new Handlebars.Exception(open.original + " doesn't match " + close.original);
598
+ }
599
+ };
600
+
601
+ Handlebars.AST.BlockNode = function(mustache, program, close) {
602
+ verifyMatch(mustache.id, close);
603
+ this.type = "block";
604
+ this.mustache = mustache;
605
+ this.program = program;
606
+ };
607
+
608
+ Handlebars.AST.InverseNode = function(mustache, program, close) {
609
+ verifyMatch(mustache.id, close);
610
+ this.type = "inverse";
611
+ this.mustache = mustache;
612
+ this.program = program;
613
+ };
614
+
615
+ Handlebars.AST.ContentNode = function(string) {
616
+ this.type = "content";
617
+ this.string = string;
618
+ };
619
+
620
+ Handlebars.AST.HashNode = function(pairs) {
621
+ this.type = "hash";
622
+ this.pairs = pairs;
623
+ };
624
+
625
+ Handlebars.AST.IdNode = function(parts) {
626
+ this.type = "ID";
627
+ this.original = parts.join(".");
628
+
629
+ var dig = [], depth = 0;
630
+
631
+ for(var i=0,l=parts.length; i<l; i++) {
632
+ var part = parts[i];
633
+
634
+ if(part === "..") { depth++; }
635
+ else if(part === "." || part === "this") { this.isScoped = true; }
636
+ else { dig.push(part); }
637
+ }
638
+
639
+ this.parts = dig;
640
+ this.string = dig.join('.');
641
+ this.depth = depth;
642
+ this.isSimple = (dig.length === 1) && (depth === 0);
643
+ };
644
+
645
+ Handlebars.AST.StringNode = function(string) {
646
+ this.type = "STRING";
647
+ this.string = string;
648
+ };
649
+
650
+ Handlebars.AST.IntegerNode = function(integer) {
651
+ this.type = "INTEGER";
652
+ this.integer = integer;
653
+ };
654
+
655
+ Handlebars.AST.BooleanNode = function(bool) {
656
+ this.type = "BOOLEAN";
657
+ this.bool = bool;
658
+ };
659
+
660
+ Handlebars.AST.CommentNode = function(comment) {
661
+ this.type = "comment";
662
+ this.comment = comment;
663
+ };
664
+
665
+ })();;
666
+ // lib/handlebars/utils.js
667
+ Handlebars.Exception = function(message) {
668
+ var tmp = Error.prototype.constructor.apply(this, arguments);
669
+
670
+ for (var p in tmp) {
671
+ if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; }
672
+ }
673
+ };
674
+ Handlebars.Exception.prototype = new Error;
675
+
676
+ // Build out our basic SafeString type
677
+ Handlebars.SafeString = function(string) {
678
+ this.string = string;
679
+ };
680
+ Handlebars.SafeString.prototype.toString = function() {
681
+ return this.string.toString();
682
+ };
683
+
684
+ (function() {
685
+ var escape = {
686
+ "<": "&lt;",
687
+ ">": "&gt;",
688
+ '"': "&quot;",
689
+ "'": "&#x27;",
690
+ "`": "&#x60;"
691
+ };
692
+
693
+ var badChars = /&(?!\w+;)|[<>"'`]/g;
694
+ var possible = /[&<>"'`]/;
695
+
696
+ var escapeChar = function(chr) {
697
+ return escape[chr] || "&amp;";
698
+ };
699
+
700
+ Handlebars.Utils = {
701
+ escapeExpression: function(string) {
702
+ // don't escape SafeStrings, since they're already safe
703
+ if (string instanceof Handlebars.SafeString) {
704
+ return string.toString();
705
+ } else if (string == null || string === false) {
706
+ return "";
707
+ }
708
+
709
+ if(!possible.test(string)) { return string; }
710
+ return string.replace(badChars, escapeChar);
711
+ },
712
+
713
+ isEmpty: function(value) {
714
+ if (typeof value === "undefined") {
715
+ return true;
716
+ } else if (value === null) {
717
+ return true;
718
+ } else if (value === false) {
719
+ return true;
720
+ } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
721
+ return true;
722
+ } else {
723
+ return false;
724
+ }
725
+ }
726
+ };
727
+ })();;
728
+ // lib/handlebars/compiler/compiler.js
729
+ Handlebars.Compiler = function() {};
730
+ Handlebars.JavaScriptCompiler = function() {};
731
+
732
+ (function(Compiler, JavaScriptCompiler) {
733
+ Compiler.OPCODE_MAP = {
734
+ appendContent: 1,
735
+ getContext: 2,
736
+ lookupWithHelpers: 3,
737
+ lookup: 4,
738
+ append: 5,
739
+ invokeMustache: 6,
740
+ appendEscaped: 7,
741
+ pushString: 8,
742
+ truthyOrFallback: 9,
743
+ functionOrFallback: 10,
744
+ invokeProgram: 11,
745
+ invokePartial: 12,
746
+ push: 13,
747
+ assignToHash: 15,
748
+ pushStringParam: 16
749
+ };
750
+
751
+ Compiler.MULTI_PARAM_OPCODES = {
752
+ appendContent: 1,
753
+ getContext: 1,
754
+ lookupWithHelpers: 2,
755
+ lookup: 1,
756
+ invokeMustache: 3,
757
+ pushString: 1,
758
+ truthyOrFallback: 1,
759
+ functionOrFallback: 1,
760
+ invokeProgram: 3,
761
+ invokePartial: 1,
762
+ push: 1,
763
+ assignToHash: 1,
764
+ pushStringParam: 1
765
+ };
766
+
767
+ Compiler.DISASSEMBLE_MAP = {};
768
+
769
+ for(var prop in Compiler.OPCODE_MAP) {
770
+ var value = Compiler.OPCODE_MAP[prop];
771
+ Compiler.DISASSEMBLE_MAP[value] = prop;
772
+ }
773
+
774
+ Compiler.multiParamSize = function(code) {
775
+ return Compiler.MULTI_PARAM_OPCODES[Compiler.DISASSEMBLE_MAP[code]];
776
+ };
777
+
778
+ Compiler.prototype = {
779
+ compiler: Compiler,
780
+
781
+ disassemble: function() {
782
+ var opcodes = this.opcodes, opcode, nextCode;
783
+ var out = [], str, name, value;
784
+
785
+ for(var i=0, l=opcodes.length; i<l; i++) {
786
+ opcode = opcodes[i];
787
+
788
+ if(opcode === 'DECLARE') {
789
+ name = opcodes[++i];
790
+ value = opcodes[++i];
791
+ out.push("DECLARE " + name + " = " + value);
792
+ } else {
793
+ str = Compiler.DISASSEMBLE_MAP[opcode];
794
+
795
+ var extraParams = Compiler.multiParamSize(opcode);
796
+ var codes = [];
797
+
798
+ for(var j=0; j<extraParams; j++) {
799
+ nextCode = opcodes[++i];
800
+
801
+ if(typeof nextCode === "string") {
802
+ nextCode = "\"" + nextCode.replace("\n", "\\n") + "\"";
803
+ }
804
+
805
+ codes.push(nextCode);
806
+ }
807
+
808
+ str = str + " " + codes.join(" ");
809
+
810
+ out.push(str);
811
+ }
812
+ }
813
+
814
+ return out.join("\n");
815
+ },
816
+
817
+ guid: 0,
818
+
819
+ compile: function(program, options) {
820
+ this.children = [];
821
+ this.depths = {list: []};
822
+ this.options = options;
823
+
824
+ // These changes will propagate to the other compiler components
825
+ var knownHelpers = this.options.knownHelpers;
826
+ this.options.knownHelpers = {
827
+ 'helperMissing': true,
828
+ 'blockHelperMissing': true,
829
+ 'each': true,
830
+ 'if': true,
831
+ 'unless': true,
832
+ 'with': true
833
+ };
834
+ if (knownHelpers) {
835
+ for (var name in knownHelpers) {
836
+ this.options.knownHelpers[name] = knownHelpers[name];
837
+ }
838
+ }
839
+
840
+ return this.program(program);
841
+ },
842
+
843
+ accept: function(node) {
844
+ return this[node.type](node);
845
+ },
846
+
847
+ program: function(program) {
848
+ var statements = program.statements, statement;
849
+ this.opcodes = [];
850
+
851
+ for(var i=0, l=statements.length; i<l; i++) {
852
+ statement = statements[i];
853
+ this[statement.type](statement);
854
+ }
855
+ this.isSimple = l === 1;
856
+
857
+ this.depths.list = this.depths.list.sort(function(a, b) {
858
+ return a - b;
859
+ });
860
+
861
+ return this;
862
+ },
863
+
864
+ compileProgram: function(program) {
865
+ var result = new this.compiler().compile(program, this.options);
866
+ var guid = this.guid++;
867
+
868
+ this.usePartial = this.usePartial || result.usePartial;
869
+
870
+ this.children[guid] = result;
871
+
872
+ for(var i=0, l=result.depths.list.length; i<l; i++) {
873
+ depth = result.depths.list[i];
874
+
875
+ if(depth < 2) { continue; }
876
+ else { this.addDepth(depth - 1); }
877
+ }
878
+
879
+ return guid;
880
+ },
881
+
882
+ block: function(block) {
883
+ var mustache = block.mustache;
884
+ var depth, child, inverse, inverseGuid;
885
+
886
+ var params = this.setupStackForMustache(mustache);
887
+
888
+ var programGuid = this.compileProgram(block.program);
889
+
890
+ if(block.program.inverse) {
891
+ inverseGuid = this.compileProgram(block.program.inverse);
892
+ this.declare('inverse', inverseGuid);
893
+ }
894
+
895
+ this.opcode('invokeProgram', programGuid, params.length, !!mustache.hash);
896
+ this.declare('inverse', null);
897
+ this.opcode('append');
898
+ },
899
+
900
+ inverse: function(block) {
901
+ var params = this.setupStackForMustache(block.mustache);
902
+
903
+ var programGuid = this.compileProgram(block.program);
904
+
905
+ this.declare('inverse', programGuid);
906
+
907
+ this.opcode('invokeProgram', null, params.length, !!block.mustache.hash);
908
+ this.opcode('append');
909
+ },
910
+
911
+ hash: function(hash) {
912
+ var pairs = hash.pairs, pair, val;
913
+
914
+ this.opcode('push', '{}');
915
+
916
+ for(var i=0, l=pairs.length; i<l; i++) {
917
+ pair = pairs[i];
918
+ val = pair[1];
919
+
920
+ this.accept(val);
921
+ this.opcode('assignToHash', pair[0]);
922
+ }
923
+ },
924
+
925
+ partial: function(partial) {
926
+ var id = partial.id;
927
+ this.usePartial = true;
928
+
929
+ if(partial.context) {
930
+ this.ID(partial.context);
931
+ } else {
932
+ this.opcode('push', 'depth0');
933
+ }
934
+
935
+ this.opcode('invokePartial', id.original);
936
+ this.opcode('append');
937
+ },
938
+
939
+ content: function(content) {
940
+ this.opcode('appendContent', content.string);
941
+ },
942
+
943
+ mustache: function(mustache) {
944
+ var params = this.setupStackForMustache(mustache);
945
+
946
+ this.opcode('invokeMustache', params.length, mustache.id.original, !!mustache.hash);
947
+
948
+ if(mustache.escaped) {
949
+ this.opcode('appendEscaped');
950
+ } else {
951
+ this.opcode('append');
952
+ }
953
+ },
954
+
955
+ ID: function(id) {
956
+ this.addDepth(id.depth);
957
+
958
+ this.opcode('getContext', id.depth);
959
+
960
+ this.opcode('lookupWithHelpers', id.parts[0] || null, id.isScoped || false);
961
+
962
+ for(var i=1, l=id.parts.length; i<l; i++) {
963
+ this.opcode('lookup', id.parts[i]);
964
+ }
965
+ },
966
+
967
+ STRING: function(string) {
968
+ this.opcode('pushString', string.string);
969
+ },
970
+
971
+ INTEGER: function(integer) {
972
+ this.opcode('push', integer.integer);
973
+ },
974
+
975
+ BOOLEAN: function(bool) {
976
+ this.opcode('push', bool.bool);
977
+ },
978
+
979
+ comment: function() {},
980
+
981
+ // HELPERS
982
+ pushParams: function(params) {
983
+ var i = params.length, param;
984
+
985
+ while(i--) {
986
+ param = params[i];
987
+
988
+ if(this.options.stringParams) {
989
+ if(param.depth) {
990
+ this.addDepth(param.depth);
991
+ }
992
+
993
+ this.opcode('getContext', param.depth || 0);
994
+ this.opcode('pushStringParam', param.string);
995
+ } else {
996
+ this[param.type](param);
997
+ }
998
+ }
999
+ },
1000
+
1001
+ opcode: function(name, val1, val2, val3) {
1002
+ this.opcodes.push(Compiler.OPCODE_MAP[name]);
1003
+ if(val1 !== undefined) { this.opcodes.push(val1); }
1004
+ if(val2 !== undefined) { this.opcodes.push(val2); }
1005
+ if(val3 !== undefined) { this.opcodes.push(val3); }
1006
+ },
1007
+
1008
+ declare: function(name, value) {
1009
+ this.opcodes.push('DECLARE');
1010
+ this.opcodes.push(name);
1011
+ this.opcodes.push(value);
1012
+ },
1013
+
1014
+ addDepth: function(depth) {
1015
+ if(depth === 0) { return; }
1016
+
1017
+ if(!this.depths[depth]) {
1018
+ this.depths[depth] = true;
1019
+ this.depths.list.push(depth);
1020
+ }
1021
+ },
1022
+
1023
+ setupStackForMustache: function(mustache) {
1024
+ var params = mustache.params;
1025
+
1026
+ this.pushParams(params);
1027
+
1028
+ if(mustache.hash) {
1029
+ this.hash(mustache.hash);
1030
+ }
1031
+
1032
+ this.ID(mustache.id);
1033
+
1034
+ return params;
1035
+ }
1036
+ };
1037
+
1038
+ JavaScriptCompiler.prototype = {
1039
+ // PUBLIC API: You can override these methods in a subclass to provide
1040
+ // alternative compiled forms for name lookup and buffering semantics
1041
+ nameLookup: function(parent, name, type) {
1042
+ if(JavaScriptCompiler.RESERVED_WORDS[name] || name.indexOf('-') !== -1 || !isNaN(name)) {
1043
+ return parent + "['" + name + "']";
1044
+ } else if (/^[0-9]+$/.test(name)) {
1045
+ return parent + "[" + name + "]";
1046
+ } else {
1047
+ return parent + "." + name;
1048
+ }
1049
+ },
1050
+
1051
+ appendToBuffer: function(string) {
1052
+ if (this.environment.isSimple) {
1053
+ return "return " + string + ";";
1054
+ } else {
1055
+ return "buffer += " + string + ";";
1056
+ }
1057
+ },
1058
+
1059
+ initializeBuffer: function() {
1060
+ return this.quotedString("");
1061
+ },
1062
+ // END PUBLIC API
1063
+
1064
+ compile: function(environment, options, context, asObject) {
1065
+ this.environment = environment;
1066
+ this.options = options || {};
1067
+
1068
+ this.name = this.environment.name;
1069
+ this.isChild = !!context;
1070
+ this.context = context || {
1071
+ programs: [],
1072
+ aliases: { self: 'this' },
1073
+ registers: {list: []}
1074
+ };
1075
+
1076
+ this.preamble();
1077
+
1078
+ this.stackSlot = 0;
1079
+ this.stackVars = [];
1080
+
1081
+ this.compileChildren(environment, options);
1082
+
1083
+ var opcodes = environment.opcodes, opcode;
1084
+
1085
+ this.i = 0;
1086
+
1087
+ for(l=opcodes.length; this.i<l; this.i++) {
1088
+ opcode = this.nextOpcode(0);
1089
+
1090
+ if(opcode[0] === 'DECLARE') {
1091
+ this.i = this.i + 2;
1092
+ this[opcode[1]] = opcode[2];
1093
+ } else {
1094
+ this.i = this.i + opcode[1].length;
1095
+ this[opcode[0]].apply(this, opcode[1]);
1096
+ }
1097
+ }
1098
+
1099
+ return this.createFunctionContext(asObject);
1100
+ },
1101
+
1102
+ nextOpcode: function(n) {
1103
+ var opcodes = this.environment.opcodes, opcode = opcodes[this.i + n], name, val;
1104
+ var extraParams, codes;
1105
+
1106
+ if(opcode === 'DECLARE') {
1107
+ name = opcodes[this.i + 1];
1108
+ val = opcodes[this.i + 2];
1109
+ return ['DECLARE', name, val];
1110
+ } else {
1111
+ name = Compiler.DISASSEMBLE_MAP[opcode];
1112
+
1113
+ extraParams = Compiler.multiParamSize(opcode);
1114
+ codes = [];
1115
+
1116
+ for(var j=0; j<extraParams; j++) {
1117
+ codes.push(opcodes[this.i + j + 1 + n]);
1118
+ }
1119
+
1120
+ return [name, codes];
1121
+ }
1122
+ },
1123
+
1124
+ eat: function(opcode) {
1125
+ this.i = this.i + opcode.length;
1126
+ },
1127
+
1128
+ preamble: function() {
1129
+ var out = [];
1130
+
1131
+ if (!this.isChild) {
1132
+ var copies = "helpers = helpers || Handlebars.helpers;";
1133
+ if(this.environment.usePartial) { copies = copies + " partials = partials || Handlebars.partials;"; }
1134
+ out.push(copies);
1135
+ } else {
1136
+ out.push('');
1137
+ }
1138
+
1139
+ if (!this.environment.isSimple) {
1140
+ out.push(", buffer = " + this.initializeBuffer());
1141
+ } else {
1142
+ out.push("");
1143
+ }
1144
+
1145
+ // track the last context pushed into place to allow skipping the
1146
+ // getContext opcode when it would be a noop
1147
+ this.lastContext = 0;
1148
+ this.source = out;
1149
+ },
1150
+
1151
+ createFunctionContext: function(asObject) {
1152
+ var locals = this.stackVars;
1153
+ if (!this.isChild) {
1154
+ locals = locals.concat(this.context.registers.list);
1155
+ }
1156
+
1157
+ if(locals.length > 0) {
1158
+ this.source[1] = this.source[1] + ", " + locals.join(", ");
1159
+ }
1160
+
1161
+ // Generate minimizer alias mappings
1162
+ if (!this.isChild) {
1163
+ var aliases = []
1164
+ for (var alias in this.context.aliases) {
1165
+ this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1166
+ }
1167
+ }
1168
+
1169
+ if (this.source[1]) {
1170
+ this.source[1] = "var " + this.source[1].substring(2) + ";";
1171
+ }
1172
+
1173
+ // Merge children
1174
+ if (!this.isChild) {
1175
+ this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1176
+ }
1177
+
1178
+ if (!this.environment.isSimple) {
1179
+ this.source.push("return buffer;");
1180
+ }
1181
+
1182
+ var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1183
+
1184
+ for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1185
+ params.push("depth" + this.environment.depths.list[i]);
1186
+ }
1187
+
1188
+ if(params.length === 4 && !this.environment.usePartial) { params.pop(); }
1189
+
1190
+ if (asObject) {
1191
+ params.push(this.source.join("\n "));
1192
+
1193
+ return Function.apply(this, params);
1194
+ } else {
1195
+ var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + this.source.join("\n ") + '}';
1196
+ Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1197
+ return functionSource;
1198
+ }
1199
+ },
1200
+
1201
+ appendContent: function(content) {
1202
+ this.source.push(this.appendToBuffer(this.quotedString(content)));
1203
+ },
1204
+
1205
+ append: function() {
1206
+ var local = this.popStack();
1207
+ this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1208
+ if (this.environment.isSimple) {
1209
+ this.source.push("else { " + this.appendToBuffer("''") + " }");
1210
+ }
1211
+ },
1212
+
1213
+ appendEscaped: function() {
1214
+ var opcode = this.nextOpcode(1), extra = "";
1215
+ this.context.aliases.escapeExpression = 'this.escapeExpression';
1216
+
1217
+ if(opcode[0] === 'appendContent') {
1218
+ extra = " + " + this.quotedString(opcode[1][0]);
1219
+ this.eat(opcode);
1220
+ }
1221
+
1222
+ this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra));
1223
+ },
1224
+
1225
+ getContext: function(depth) {
1226
+ if(this.lastContext !== depth) {
1227
+ this.lastContext = depth;
1228
+ }
1229
+ },
1230
+
1231
+ lookupWithHelpers: function(name, isScoped) {
1232
+ if(name) {
1233
+ var topStack = this.nextStack();
1234
+
1235
+ this.usingKnownHelper = false;
1236
+
1237
+ var toPush;
1238
+ if (!isScoped && this.options.knownHelpers[name]) {
1239
+ toPush = topStack + " = " + this.nameLookup('helpers', name, 'helper');
1240
+ this.usingKnownHelper = true;
1241
+ } else if (isScoped || this.options.knownHelpersOnly) {
1242
+ toPush = topStack + " = " + this.nameLookup('depth' + this.lastContext, name, 'context');
1243
+ } else {
1244
+ toPush = topStack + " = "
1245
+ + this.nameLookup('helpers', name, 'helper')
1246
+ + " || "
1247
+ + this.nameLookup('depth' + this.lastContext, name, 'context');
1248
+ }
1249
+
1250
+ this.source.push(toPush);
1251
+ } else {
1252
+ this.pushStack('depth' + this.lastContext);
1253
+ }
1254
+ },
1255
+
1256
+ lookup: function(name) {
1257
+ var topStack = this.topStack();
1258
+ this.source.push(topStack + " = " + this.nameLookup(topStack, name, 'context') + ";");
1259
+ },
1260
+
1261
+ pushStringParam: function(string) {
1262
+ this.pushStack('depth' + this.lastContext);
1263
+ this.pushString(string);
1264
+ },
1265
+
1266
+ pushString: function(string) {
1267
+ this.pushStack(this.quotedString(string));
1268
+ },
1269
+
1270
+ push: function(name) {
1271
+ this.pushStack(name);
1272
+ },
1273
+
1274
+ invokeMustache: function(paramSize, original, hasHash) {
1275
+ this.populateParams(paramSize, this.quotedString(original), "{}", null, hasHash, function(nextStack, helperMissingString, id) {
1276
+ if (!this.usingKnownHelper) {
1277
+ this.context.aliases.helperMissing = 'helpers.helperMissing';
1278
+ this.context.aliases.undef = 'void 0';
1279
+ this.source.push("else if(" + id + "=== undef) { " + nextStack + " = helperMissing.call(" + helperMissingString + "); }");
1280
+ if (nextStack !== id) {
1281
+ this.source.push("else { " + nextStack + " = " + id + "; }");
1282
+ }
1283
+ }
1284
+ });
1285
+ },
1286
+
1287
+ invokeProgram: function(guid, paramSize, hasHash) {
1288
+ var inverse = this.programExpression(this.inverse);
1289
+ var mainProgram = this.programExpression(guid);
1290
+
1291
+ this.populateParams(paramSize, null, mainProgram, inverse, hasHash, function(nextStack, helperMissingString, id) {
1292
+ if (!this.usingKnownHelper) {
1293
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1294
+ this.source.push("else { " + nextStack + " = blockHelperMissing.call(" + helperMissingString + "); }");
1295
+ }
1296
+ });
1297
+ },
1298
+
1299
+ populateParams: function(paramSize, helperId, program, inverse, hasHash, fn) {
1300
+ var needsRegister = hasHash || this.options.stringParams || inverse || this.options.data;
1301
+ var id = this.popStack(), nextStack;
1302
+ var params = [], param, stringParam, stringOptions;
1303
+
1304
+ if (needsRegister) {
1305
+ this.register('tmp1', program);
1306
+ stringOptions = 'tmp1';
1307
+ } else {
1308
+ stringOptions = '{ hash: {} }';
1309
+ }
1310
+
1311
+ if (needsRegister) {
1312
+ var hash = (hasHash ? this.popStack() : '{}');
1313
+ this.source.push('tmp1.hash = ' + hash + ';');
1314
+ }
1315
+
1316
+ if(this.options.stringParams) {
1317
+ this.source.push('tmp1.contexts = [];');
1318
+ }
1319
+
1320
+ for(var i=0; i<paramSize; i++) {
1321
+ param = this.popStack();
1322
+ params.push(param);
1323
+
1324
+ if(this.options.stringParams) {
1325
+ this.source.push('tmp1.contexts.push(' + this.popStack() + ');');
1326
+ }
1327
+ }
1328
+
1329
+ if(inverse) {
1330
+ this.source.push('tmp1.fn = tmp1;');
1331
+ this.source.push('tmp1.inverse = ' + inverse + ';');
1332
+ }
1333
+
1334
+ if(this.options.data) {
1335
+ this.source.push('tmp1.data = data;');
1336
+ }
1337
+
1338
+ params.push(stringOptions);
1339
+
1340
+ this.populateCall(params, id, helperId || id, fn);
1341
+ },
1342
+
1343
+ populateCall: function(params, id, helperId, fn) {
1344
+ var paramString = ["depth0"].concat(params).join(", ");
1345
+ var helperMissingString = ["depth0"].concat(helperId).concat(params).join(", ");
1346
+
1347
+ var nextStack = this.nextStack();
1348
+
1349
+ if (this.usingKnownHelper) {
1350
+ this.source.push(nextStack + " = " + id + ".call(" + paramString + ");");
1351
+ } else {
1352
+ this.context.aliases.functionType = '"function"';
1353
+ this.source.push("if(typeof " + id + " === functionType) { " + nextStack + " = " + id + ".call(" + paramString + "); }");
1354
+ }
1355
+ fn.call(this, nextStack, helperMissingString, id);
1356
+ this.usingKnownHelper = false;
1357
+ },
1358
+
1359
+ invokePartial: function(context) {
1360
+ this.pushStack("self.invokePartial(" + this.nameLookup('partials', context, 'partial') + ", '" + context + "', " + this.popStack() + ", helpers, partials);");
1361
+ },
1362
+
1363
+ assignToHash: function(key) {
1364
+ var value = this.popStack();
1365
+ var hash = this.topStack();
1366
+
1367
+ this.source.push(hash + "['" + key + "'] = " + value + ";");
1368
+ },
1369
+
1370
+ // HELPERS
1371
+
1372
+ compiler: JavaScriptCompiler,
1373
+
1374
+ compileChildren: function(environment, options) {
1375
+ var children = environment.children, child, compiler;
1376
+
1377
+ for(var i=0, l=children.length; i<l; i++) {
1378
+ child = children[i];
1379
+ compiler = new this.compiler();
1380
+
1381
+ this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
1382
+ var index = this.context.programs.length;
1383
+ child.index = index;
1384
+ child.name = 'program' + index;
1385
+ this.context.programs[index] = compiler.compile(child, options, this.context);
1386
+ }
1387
+ },
1388
+
1389
+ programExpression: function(guid) {
1390
+ if(guid == null) { return "self.noop"; }
1391
+
1392
+ var child = this.environment.children[guid],
1393
+ depths = child.depths.list;
1394
+ var programParams = [child.index, child.name, "data"];
1395
+
1396
+ for(var i=0, l = depths.length; i<l; i++) {
1397
+ depth = depths[i];
1398
+
1399
+ if(depth === 1) { programParams.push("depth0"); }
1400
+ else { programParams.push("depth" + (depth - 1)); }
1401
+ }
1402
+
1403
+ if(depths.length === 0) {
1404
+ return "self.program(" + programParams.join(", ") + ")";
1405
+ } else {
1406
+ programParams.shift();
1407
+ return "self.programWithDepth(" + programParams.join(", ") + ")";
1408
+ }
1409
+ },
1410
+
1411
+ register: function(name, val) {
1412
+ this.useRegister(name);
1413
+ this.source.push(name + " = " + val + ";");
1414
+ },
1415
+
1416
+ useRegister: function(name) {
1417
+ if(!this.context.registers[name]) {
1418
+ this.context.registers[name] = true;
1419
+ this.context.registers.list.push(name);
1420
+ }
1421
+ },
1422
+
1423
+ pushStack: function(item) {
1424
+ this.source.push(this.nextStack() + " = " + item + ";");
1425
+ return "stack" + this.stackSlot;
1426
+ },
1427
+
1428
+ nextStack: function() {
1429
+ this.stackSlot++;
1430
+ if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1431
+ return "stack" + this.stackSlot;
1432
+ },
1433
+
1434
+ popStack: function() {
1435
+ return "stack" + this.stackSlot--;
1436
+ },
1437
+
1438
+ topStack: function() {
1439
+ return "stack" + this.stackSlot;
1440
+ },
1441
+
1442
+ quotedString: function(str) {
1443
+ return '"' + str
1444
+ .replace(/\\/g, '\\\\')
1445
+ .replace(/"/g, '\\"')
1446
+ .replace(/\n/g, '\\n')
1447
+ .replace(/\r/g, '\\r') + '"';
1448
+ }
1449
+ };
1450
+
1451
+ var reservedWords = ("break case catch continue default delete do else finally " +
1452
+ "for function if in instanceof new return switch this throw " +
1453
+ "try typeof var void while with null true false").split(" ");
1454
+
1455
+ compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
1456
+
1457
+ for(var i=0, l=reservedWords.length; i<l; i++) {
1458
+ compilerWords[reservedWords[i]] = true;
1459
+ }
1460
+
1461
+ })(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
1462
+
1463
+ Handlebars.precompile = function(string, options) {
1464
+ options = options || {};
1465
+
1466
+ var ast = Handlebars.parse(string);
1467
+ var environment = new Handlebars.Compiler().compile(ast, options);
1468
+ return new Handlebars.JavaScriptCompiler().compile(environment, options);
1469
+ };
1470
+
1471
+ Handlebars.compile = function(string, options) {
1472
+ options = options || {};
1473
+
1474
+ var ast = Handlebars.parse(string);
1475
+ var environment = new Handlebars.Compiler().compile(ast, options);
1476
+ var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
1477
+ return Handlebars.template(templateSpec);
1478
+ };
1479
+ ;
1480
+ // lib/handlebars/vm.js
1481
+ Handlebars.VM = {
1482
+ template: function(templateSpec) {
1483
+ // Just add water
1484
+ var container = {
1485
+ escapeExpression: Handlebars.Utils.escapeExpression,
1486
+ invokePartial: Handlebars.VM.invokePartial,
1487
+ programs: [],
1488
+ program: function(i, fn, data) {
1489
+ var programWrapper = this.programs[i];
1490
+ if(data) {
1491
+ return Handlebars.VM.program(fn, data);
1492
+ } else if(programWrapper) {
1493
+ return programWrapper;
1494
+ } else {
1495
+ programWrapper = this.programs[i] = Handlebars.VM.program(fn);
1496
+ return programWrapper;
1497
+ }
1498
+ },
1499
+ programWithDepth: Handlebars.VM.programWithDepth,
1500
+ noop: Handlebars.VM.noop
1501
+ };
1502
+
1503
+ return function(context, options) {
1504
+ options = options || {};
1505
+ return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
1506
+ };
1507
+ },
1508
+
1509
+ programWithDepth: function(fn, data, $depth) {
1510
+ var args = Array.prototype.slice.call(arguments, 2);
1511
+
1512
+ return function(context, options) {
1513
+ options = options || {};
1514
+
1515
+ return fn.apply(this, [context, options.data || data].concat(args));
1516
+ };
1517
+ },
1518
+ program: function(fn, data) {
1519
+ return function(context, options) {
1520
+ options = options || {};
1521
+
1522
+ return fn(context, options.data || data);
1523
+ };
1524
+ },
1525
+ noop: function() { return ""; },
1526
+ invokePartial: function(partial, name, context, helpers, partials) {
1527
+ if(partial === undefined) {
1528
+ throw new Handlebars.Exception("The partial " + name + " could not be found");
1529
+ } else if(partial instanceof Function) {
1530
+ return partial(context, {helpers: helpers, partials: partials});
1531
+ } else if (!Handlebars.compile) {
1532
+ throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in vm mode");
1533
+ } else {
1534
+ partials[name] = Handlebars.compile(partial);
1535
+ return partials[name](context, {helpers: helpers, partials: partials});
1536
+ }
1537
+ }
1538
+ };
1539
+
1540
+ Handlebars.template = Handlebars.VM.template;
1541
+
1542
+ var SC = { Handlebars : {} };
1543
+ this.SC = SC;
1544
+
1545
+ SC.Handlebars.Compiler = function() {};
1546
+ SC.Handlebars.Compiler.prototype = Object.create( Handlebars.Compiler.prototype );
1547
+ SC.Handlebars.Compiler.prototype.compiler = SC.Handlebars.Compiler;
1548
+
1549
+ SC.Handlebars.JavaScriptCompiler = function() {};
1550
+ SC.Handlebars.JavaScriptCompiler.prototype = Object.create(Handlebars.JavaScriptCompiler.prototype);
1551
+ SC.Handlebars.JavaScriptCompiler.prototype.compiler = SC.Handlebars.JavaScriptCompiler;
1552
+
1553
+ /**
1554
+ Override the default property lookup semantics of Handlebars.
1555
+
1556
+ By default, Handlebars uses object[property] to look up properties. SproutCore's Handlebars
1557
+ uses SC.get().
1558
+
1559
+ @private
1560
+ */
1561
+ SC.Handlebars.JavaScriptCompiler.prototype.nameLookup = function(parent, name, type) {
1562
+ if (type === 'context') {
1563
+ return "SC.get(" + parent + ", " + this.quotedString(name) + ");";
1564
+ } else {
1565
+ return Handlebars.JavaScriptCompiler.prototype.nameLookup.call(this, parent, name, type);
1566
+ }
1567
+ };
1568
+
1569
+ SC.Handlebars.JavaScriptCompiler.prototype.initializeBuffer = function() {
1570
+ return "''";
1571
+ };
1572
+
1573
+ /**
1574
+ Override the default buffer for SproutCore Handlebars. By default, Handlebars creates
1575
+ an empty String at the beginning of each invocation and appends to it. SproutCore's
1576
+ Handlebars overrides this to append to a single shared buffer.
1577
+
1578
+ @private
1579
+ */
1580
+ SC.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
1581
+ return "data.buffer.push("+string+");";
1582
+ };
1583
+
1584
+ /**
1585
+ Rewrite simple mustaches from {{foo}} to {{bind "foo"}}. This means that all simple
1586
+ mustaches in SproutCore's Handlebars will also set up an observer to keep the DOM
1587
+ up to date when the underlying property changes.
1588
+
1589
+ @private
1590
+ */
1591
+ SC.Handlebars.Compiler.prototype.mustache = function(mustache) {
1592
+ if (mustache.params.length || mustache.hash) {
1593
+ return Handlebars.Compiler.prototype.mustache.call(this, mustache);
1594
+ } else {
1595
+ var id = new Handlebars.AST.IdNode(['bind']);
1596
+
1597
+ // Update the mustache node to include a hash value indicating whether the original node
1598
+ // was escaped. This will allow us to properly escape values when the underlying value
1599
+ // changes and we need to re-render the value.
1600
+ if(mustache.escaped) {
1601
+ mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
1602
+ mustache.hash.pairs.push(["escaped", new Handlebars.AST.StringNode("true")]);
1603
+ }
1604
+ mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
1605
+ return Handlebars.Compiler.prototype.mustache.call(this, mustache);
1606
+ }
1607
+ };
1608
+
1609
+ SC.Handlebars.precompile = function(string) {
1610
+ var options = { data: true, stringParams: true };
1611
+
1612
+ var ast = Handlebars.parse(string);
1613
+
1614
+ var environment = new SC.Handlebars.Compiler().compile(ast, options);
1615
+ return new SC.Handlebars.JavaScriptCompiler().compile(environment, options);
1616
+ };
1617
+