handlebars_rb 0.0.1

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