Skip to content
This repository
Browse code

Update for Handlebars 1.0.rc.1

  • Loading branch information...
commit 976bddd1020ba3f214ce1c42642d384da9352aed 1 parent b1a3a00
Peter Wagenet wagenet authored
2  benchmarks/runner.js
@@ -15,7 +15,7 @@ function makeiframe(emberPath, suitePath, suiteCode, profile, callback) {
15 15 write("<title>" + name + "</title>");
16 16 write("<script src='../lib/jquery-1.7.2.js'></script>");
17 17 write("<script>ENV = {VIEW_PRESERVES_CONTEXT: true};</script>");
18   - write("<script src='../lib/handlebars-1.0.0.beta.6.js'></script>");
  18 + write("<script src='../lib/handlebars-1.0.rc.1.js'></script>");
19 19 write("<script src='" + emberPath + "'></script>");
20 20 write("<script src='benchmark.js'></script>");
21 21 write("<script src='iframe_runner.js'></script>");
1,196 lib/handlebars-1.0.0.beta.6.js → lib/handlebars-1.0.rc.1.js
... ... @@ -1,7 +1,11 @@
1 1 // lib/handlebars/base.js
2   -var Handlebars = {};
3 2
4   -Handlebars.VERSION = "1.0.beta.6";
  3 +/*jshint eqnull:true*/
  4 +this.Handlebars = {};
  5 +
  6 +(function(Handlebars) {
  7 +
  8 +Handlebars.VERSION = "1.0.rc.1";
5 9
6 10 Handlebars.helpers = {};
7 11 Handlebars.partials = {};
@@ -40,25 +44,36 @@ Handlebars.registerHelper('blockHelperMissing', function(context, options) {
40 44 return inverse(this);
41 45 } else if(type === "[object Array]") {
42 46 if(context.length > 0) {
43   - for(var i=0, j=context.length; i<j; i++) {
44   - ret = ret + fn(context[i]);
45   - }
  47 + return Handlebars.helpers.each(context, options);
46 48 } else {
47   - ret = inverse(this);
  49 + return inverse(this);
48 50 }
49   - return ret;
50 51 } else {
51 52 return fn(context);
52 53 }
53 54 });
54 55
  56 +Handlebars.K = function() {};
  57 +
  58 +Handlebars.createFrame = Object.create || function(object) {
  59 + Handlebars.K.prototype = object;
  60 + var obj = new Handlebars.K();
  61 + Handlebars.K.prototype = null;
  62 + return obj;
  63 +};
  64 +
55 65 Handlebars.registerHelper('each', function(context, options) {
56 66 var fn = options.fn, inverse = options.inverse;
57   - var ret = "";
  67 + var ret = "", data;
  68 +
  69 + if (options.data) {
  70 + data = Handlebars.createFrame(options.data);
  71 + }
58 72
59 73 if(context && context.length > 0) {
60 74 for(var i=0, j=context.length; i<j; i++) {
61   - ret = ret + fn(context[i]);
  75 + if (data) { data.index = i; }
  76 + ret = ret + fn(context[i], { data: data });
62 77 }
63 78 } else {
64 79 ret = inverse(this);
@@ -92,104 +107,111 @@ Handlebars.registerHelper('with', function(context, options) {
92 107 Handlebars.registerHelper('log', function(context) {
93 108 Handlebars.log(context);
94 109 });
  110 +
  111 +}(this.Handlebars));
95 112 ;
96 113 // lib/handlebars/compiler/parser.js
97 114 /* Jison generated parser */
98 115 var handlebars = (function(){
99   -
100 116 var parser = {trace: function trace() { },
101 117 yy: {},
102   -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},
103   -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"},
104   -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]],
  118 +symbols_: {"error":2,"root":3,"program":4,"EOF":5,"statements":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"OPEN_PARTIAL":24,"params":25,"hash":26,"DATA":27,"param":28,"STRING":29,"INTEGER":30,"BOOLEAN":31,"hashSegments":32,"hashSegment":33,"ID":34,"EQUALS":35,"pathSegments":36,"SEP":37,"$accept":0,"$end":1},
  119 +terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",27:"DATA",29:"STRING",30:"INTEGER",31:"BOOLEAN",34:"ID",35:"EQUALS",37:"SEP"},
  120 +productions_: [0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[17,1],[25,2],[25,1],[28,1],[28,1],[28,1],[28,1],[28,1],[26,1],[32,2],[32,1],[33,3],[33,3],[33,3],[33,3],[33,3],[21,1],[36,3],[36,1]],
105 121 performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
106 122
107 123 var $0 = $$.length - 1;
108 124 switch (yystate) {
109   -case 1: return $$[$0-1]
  125 +case 1: return $$[$0-1];
110 126 break;
111   -case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0])
  127 +case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]);
112 128 break;
113   -case 3: this.$ = new yy.ProgramNode($$[$0])
  129 +case 3: this.$ = new yy.ProgramNode($$[$0]);
114 130 break;
115   -case 4: this.$ = new yy.ProgramNode([])
  131 +case 4: this.$ = new yy.ProgramNode([]);
116 132 break;
117   -case 5: this.$ = [$$[$0]]
  133 +case 5: this.$ = [$$[$0]];
118 134 break;
119   -case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]
  135 +case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
120 136 break;
121   -case 7: this.$ = new yy.InverseNode($$[$0-2], $$[$0-1], $$[$0])
  137 +case 7: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]);
122 138 break;
123   -case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0])
  139 +case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]);
124 140 break;
125   -case 9: this.$ = $$[$0]
  141 +case 9: this.$ = $$[$0];
126 142 break;
127   -case 10: this.$ = $$[$0]
  143 +case 10: this.$ = $$[$0];
128 144 break;
129   -case 11: this.$ = new yy.ContentNode($$[$0])
  145 +case 11: this.$ = new yy.ContentNode($$[$0]);
130 146 break;
131   -case 12: this.$ = new yy.CommentNode($$[$0])
  147 +case 12: this.$ = new yy.CommentNode($$[$0]);
132 148 break;
133   -case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
  149 +case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
134 150 break;
135   -case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
  151 +case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
136 152 break;
137   -case 15: this.$ = $$[$0-1]
  153 +case 15: this.$ = $$[$0-1];
138 154 break;
139   -case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1])
  155 +case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
140 156 break;
141   -case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true)
  157 +case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true);
142 158 break;
143   -case 18: this.$ = new yy.PartialNode($$[$0-1])
  159 +case 18: this.$ = new yy.PartialNode($$[$0-1]);
144 160 break;
145   -case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1])
  161 +case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]);
146 162 break;
147 163 case 20:
148 164 break;
149   -case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]]
  165 +case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]];
  166 +break;
  167 +case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null];
150 168 break;
151   -case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null]
  169 +case 23: this.$ = [[$$[$0-1]], $$[$0]];
152 170 break;
153   -case 23: this.$ = [[$$[$0-1]], $$[$0]]
  171 +case 24: this.$ = [[$$[$0]], null];
154 172 break;
155   -case 24: this.$ = [[$$[$0]], null]
  173 +case 25: this.$ = [[new yy.DataNode($$[$0])], null];
156 174 break;
157   -case 25: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
  175 +case 26: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
158 176 break;
159   -case 26: this.$ = [$$[$0]]
  177 +case 27: this.$ = [$$[$0]];
160 178 break;
161   -case 27: this.$ = $$[$0]
  179 +case 28: this.$ = $$[$0];
162 180 break;
163   -case 28: this.$ = new yy.StringNode($$[$0])
  181 +case 29: this.$ = new yy.StringNode($$[$0]);
164 182 break;
165   -case 29: this.$ = new yy.IntegerNode($$[$0])
  183 +case 30: this.$ = new yy.IntegerNode($$[$0]);
166 184 break;
167   -case 30: this.$ = new yy.BooleanNode($$[$0])
  185 +case 31: this.$ = new yy.BooleanNode($$[$0]);
168 186 break;
169   -case 31: this.$ = new yy.HashNode($$[$0])
  187 +case 32: this.$ = new yy.DataNode($$[$0]);
170 188 break;
171   -case 32: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]
  189 +case 33: this.$ = new yy.HashNode($$[$0]);
172 190 break;
173   -case 33: this.$ = [$$[$0]]
  191 +case 34: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
174 192 break;
175   -case 34: this.$ = [$$[$0-2], $$[$0]]
  193 +case 35: this.$ = [$$[$0]];
176 194 break;
177   -case 35: this.$ = [$$[$0-2], new yy.StringNode($$[$0])]
  195 +case 36: this.$ = [$$[$0-2], $$[$0]];
178 196 break;
179   -case 36: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])]
  197 +case 37: this.$ = [$$[$0-2], new yy.StringNode($$[$0])];
180 198 break;
181   -case 37: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])]
  199 +case 38: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])];
182 200 break;
183   -case 38: this.$ = new yy.IdNode($$[$0])
  201 +case 39: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])];
184 202 break;
185   -case 39: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
  203 +case 40: this.$ = [$$[$0-2], new yy.DataNode($$[$0])];
186 204 break;
187   -case 40: this.$ = [$$[$0]]
  205 +case 41: this.$ = new yy.IdNode($$[$0]);
  206 +break;
  207 +case 42: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
  208 +break;
  209 +case 43: this.$ = [$$[$0]];
188 210 break;
189 211 }
190 212 },
191   -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]}],
192   -defaultActions: {16:[2,1],37:[2,23],53:[2,21]},
  213 +table: [{3:1,4:2,5:[2,4],6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{1:[3]},{5:[1,16]},{5:[2,3],7:17,8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,19],20:[2,3],22:[1,13],23:[1,14],24:[1,15]},{5:[2,5],14:[2,5],15:[2,5],16:[2,5],19:[2,5],20:[2,5],22:[2,5],23:[2,5],24:[2,5]},{4:20,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{4:21,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{17:22,21:23,27:[1,24],34:[1,26],36:25},{17:27,21:23,27:[1,24],34:[1,26],36:25},{17:28,21:23,27:[1,24],34:[1,26],36:25},{17:29,21:23,27:[1,24],34:[1,26],36:25},{21:30,34:[1,26],36:25},{1:[2,1]},{6:31,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{5:[2,6],14:[2,6],15:[2,6],16:[2,6],19:[2,6],20:[2,6],22:[2,6],23:[2,6],24:[2,6]},{17:22,18:[1,32],21:23,27:[1,24],34:[1,26],36:25},{10:33,20:[1,34]},{10:35,20:[1,34]},{18:[1,36]},{18:[2,24],21:41,25:37,26:38,27:[1,45],28:39,29:[1,42],30:[1,43],31:[1,44],32:40,33:46,34:[1,47],36:25},{18:[2,25]},{18:[2,41],27:[2,41],29:[2,41],30:[2,41],31:[2,41],34:[2,41],37:[1,48]},{18:[2,43],27:[2,43],29:[2,43],30:[2,43],31:[2,43],34:[2,43],37:[2,43]},{18:[1,49]},{18:[1,50]},{18:[1,51]},{18:[1,52],21:53,34:[1,26],36:25},{5:[2,2],8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,2],22:[1,13],23:[1,14],24:[1,15]},{14:[2,20],15:[2,20],16:[2,20],19:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,7],14:[2,7],15:[2,7],16:[2,7],19:[2,7],20:[2,7],22:[2,7],23:[2,7],24:[2,7]},{21:54,34:[1,26],36:25},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],24:[2,8]},{14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{18:[2,22],21:41,26:55,27:[1,45],28:56,29:[1,42],30:[1,43],31:[1,44],32:40,33:46,34:[1,47],36:25},{18:[2,23]},{18:[2,27],27:[2,27],29:[2,27],30:[2,27],31:[2,27],34:[2,27]},{18:[2,33],33:57,34:[1,58]},{18:[2,28],27:[2,28],29:[2,28],30:[2,28],31:[2,28],34:[2,28]},{18:[2,29],27:[2,29],29:[2,29],30:[2,29],31:[2,29],34:[2,29]},{18:[2,30],27:[2,30],29:[2,30],30:[2,30],31:[2,30],34:[2,30]},{18:[2,31],27:[2,31],29:[2,31],30:[2,31],31:[2,31],34:[2,31]},{18:[2,32],27:[2,32],29:[2,32],30:[2,32],31:[2,32],34:[2,32]},{18:[2,35],34:[2,35]},{18:[2,43],27:[2,43],29:[2,43],30:[2,43],31:[2,43],34:[2,43],35:[1,59],37:[2,43]},{34:[1,60]},{14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],24:[2,13]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],24:[2,16]},{5:[2,17],14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],24:[2,18]},{18:[1,61]},{18:[1,62]},{18:[2,21]},{18:[2,26],27:[2,26],29:[2,26],30:[2,26],31:[2,26],34:[2,26]},{18:[2,34],34:[2,34]},{35:[1,59]},{21:63,27:[1,67],29:[1,64],30:[1,65],31:[1,66],34:[1,26],36:25},{18:[2,42],27:[2,42],29:[2,42],30:[2,42],31:[2,42],34:[2,42],37:[2,42]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],24:[2,19]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],24:[2,15]},{18:[2,36],34:[2,36]},{18:[2,37],34:[2,37]},{18:[2,38],34:[2,38]},{18:[2,39],34:[2,39]},{18:[2,40],34:[2,40]}],
  214 +defaultActions: {16:[2,1],24:[2,25],38:[2,23],55:[2,21]},
193 215 parseError: function parseError(str, hash) {
194 216 throw new Error(str);
195 217 },
@@ -198,10 +220,12 @@ parse: function parse(input) {
198 220 this.lexer.setInput(input);
199 221 this.lexer.yy = this.yy;
200 222 this.yy.lexer = this.lexer;
  223 + this.yy.parser = this;
201 224 if (typeof this.lexer.yylloc == "undefined")
202 225 this.lexer.yylloc = {};
203 226 var yyloc = this.lexer.yylloc;
204 227 lstack.push(yyloc);
  228 + var ranges = this.lexer.options && this.lexer.options.ranges;
205 229 if (typeof this.yy.parseError === "function")
206 230 this.parseError = this.yy.parseError;
207 231 function popStack(n) {
@@ -223,20 +247,21 @@ parse: function parse(input) {
223 247 if (this.defaultActions[state]) {
224 248 action = this.defaultActions[state];
225 249 } else {
226   - if (symbol == null)
  250 + if (symbol === null || typeof symbol == "undefined") {
227 251 symbol = lex();
  252 + }
228 253 action = table[state] && table[state][symbol];
229 254 }
230 255 if (typeof action === "undefined" || !action.length || !action[0]) {
  256 + var errStr = "";
231 257 if (!recovering) {
232 258 expected = [];
233 259 for (p in table[state])
234 260 if (this.terminals_[p] && p > 2) {
235 261 expected.push("'" + this.terminals_[p] + "'");
236 262 }
237   - var errStr = "";
238 263 if (this.lexer.showPosition) {
239   - errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + this.terminals_[symbol] + "'";
  264 + errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
240 265 } else {
241 266 errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'");
242 267 }
@@ -269,6 +294,9 @@ parse: function parse(input) {
269 294 len = this.productions_[action[1]][1];
270 295 yyval.$ = vstack[vstack.length - len];
271 296 yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column};
  297 + if (ranges) {
  298 + yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
  299 + }
272 300 r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
273 301 if (typeof r !== "undefined") {
274 302 return r;
@@ -290,13 +318,13 @@ parse: function parse(input) {
290 318 }
291 319 return true;
292 320 }
293   -};/* Jison generated lexer */
  321 +};
  322 +/* Jison generated lexer */
294 323 var lexer = (function(){
295   -
296 324 var lexer = ({EOF:1,
297 325 parseError:function parseError(str, hash) {
298   - if (this.yy.parseError) {
299   - this.yy.parseError(str, hash);
  326 + if (this.yy.parser) {
  327 + this.yy.parser.parseError(str, hash);
300 328 } else {
301 329 throw new Error(str);
302 330 }
@@ -308,27 +336,64 @@ setInput:function (input) {
308 336 this.yytext = this.matched = this.match = '';
309 337 this.conditionStack = ['INITIAL'];
310 338 this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
  339 + if (this.options.ranges) this.yylloc.range = [0,0];
  340 + this.offset = 0;
311 341 return this;
312 342 },
313 343 input:function () {
314 344 var ch = this._input[0];
315   - this.yytext+=ch;
  345 + this.yytext += ch;
316 346 this.yyleng++;
317   - this.match+=ch;
318   - this.matched+=ch;
319   - var lines = ch.match(/\n/);
320   - if (lines) this.yylineno++;
  347 + this.offset++;
  348 + this.match += ch;
  349 + this.matched += ch;
  350 + var lines = ch.match(/(?:\r\n?|\n).*/g);
  351 + if (lines) {
  352 + this.yylineno++;
  353 + this.yylloc.last_line++;
  354 + } else {
  355 + this.yylloc.last_column++;
  356 + }
  357 + if (this.options.ranges) this.yylloc.range[1]++;
  358 +
321 359 this._input = this._input.slice(1);
322 360 return ch;
323 361 },
324 362 unput:function (ch) {
  363 + var len = ch.length;
  364 + var lines = ch.split(/(?:\r\n?|\n)/g);
  365 +
325 366 this._input = ch + this._input;
  367 + this.yytext = this.yytext.substr(0, this.yytext.length-len-1);
  368 + //this.yyleng -= len;
  369 + this.offset -= len;
  370 + var oldLines = this.match.split(/(?:\r\n?|\n)/g);
  371 + this.match = this.match.substr(0, this.match.length-1);
  372 + this.matched = this.matched.substr(0, this.matched.length-1);
  373 +
  374 + if (lines.length-1) this.yylineno -= lines.length-1;
  375 + var r = this.yylloc.range;
  376 +
  377 + this.yylloc = {first_line: this.yylloc.first_line,
  378 + last_line: this.yylineno+1,
  379 + first_column: this.yylloc.first_column,
  380 + last_column: lines ?
  381 + (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length:
  382 + this.yylloc.first_column - len
  383 + };
  384 +
  385 + if (this.options.ranges) {
  386 + this.yylloc.range = [r[0], r[0] + this.yyleng - len];
  387 + }
326 388 return this;
327 389 },
328 390 more:function () {
329 391 this._more = true;
330 392 return this;
331 393 },
  394 +less:function (n) {
  395 + this.unput(this.match.slice(n));
  396 + },
332 397 pastInput:function () {
333 398 var past = this.matched.substr(0, this.matched.length - this.match.length);
334 399 return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
@@ -353,6 +418,8 @@ next:function () {
353 418
354 419 var token,
355 420 match,
  421 + tempMatch,
  422 + index,
356 423 col,
357 424 lines;
358 425 if (!this._more) {
@@ -361,30 +428,39 @@ next:function () {
361 428 }
362 429 var rules = this._currentRules();
363 430 for (var i=0;i < rules.length; i++) {
364   - match = this._input.match(this.rules[rules[i]]);
365   - if (match) {
366   - lines = match[0].match(/\n.*/g);
367   - if (lines) this.yylineno += lines.length;
368   - this.yylloc = {first_line: this.yylloc.last_line,
369   - last_line: this.yylineno+1,
370   - first_column: this.yylloc.last_column,
371   - last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
372   - this.yytext += match[0];
373   - this.match += match[0];
374   - this.matches = match;
375   - this.yyleng = this.yytext.length;
376   - this._more = false;
377   - this._input = this._input.slice(match[0].length);
378   - this.matched += match[0];
379   - token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);
380   - if (token) return token;
381   - else return;
  431 + tempMatch = this._input.match(this.rules[rules[i]]);
  432 + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
  433 + match = tempMatch;
  434 + index = i;
  435 + if (!this.options.flex) break;
382 436 }
383 437 }
  438 + if (match) {
  439 + lines = match[0].match(/(?:\r\n?|\n).*/g);
  440 + if (lines) this.yylineno += lines.length;
  441 + this.yylloc = {first_line: this.yylloc.last_line,
  442 + last_line: this.yylineno+1,
  443 + first_column: this.yylloc.last_column,
  444 + last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length};
  445 + this.yytext += match[0];
  446 + this.match += match[0];
  447 + this.matches = match;
  448 + this.yyleng = this.yytext.length;
  449 + if (this.options.ranges) {
  450 + this.yylloc.range = [this.offset, this.offset += this.yyleng];
  451 + }
  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[index],this.conditionStack[this.conditionStack.length-1]);
  456 + if (this.done && this._input) this.done = false;
  457 + if (token) return token;
  458 + else return;
  459 + }
384 460 if (this._input === "") {
385 461 return this.EOF;
386 462 } else {
387   - this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
  463 + return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
388 464 {text: "", token: null, line: this.yylineno});
389 465 }
390 466 },
@@ -411,6 +487,7 @@ topState:function () {
411 487 pushState:function begin(condition) {
412 488 this.begin(condition);
413 489 }});
  490 +lexer.options = {};
414 491 lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
415 492
416 493 var YYSTATE=YY_START
@@ -423,7 +500,11 @@ case 0:
423 500 break;
424 501 case 1: return 14;
425 502 break;
426   -case 2: this.popState(); return 14;
  503 +case 2:
  504 + if(yy_.yytext.slice(-1) !== "\\") this.popState();
  505 + if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1);
  506 + return 14;
  507 +
427 508 break;
428 509 case 3: return 24;
429 510 break;
@@ -443,13 +524,13 @@ case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return
443 524 break;
444 525 case 11: return 22;
445 526 break;
446   -case 12: return 34;
  527 +case 12: return 35;
447 528 break;
448   -case 13: return 33;
  529 +case 13: return 34;
449 530 break;
450   -case 14: return 33;
  531 +case 14: return 34;
451 532 break;
452   -case 15: return 36;
  533 +case 15: return 37;
453 534 break;
454 535 case 16: /*ignore whitespace*/
455 536 break;
@@ -457,40 +538,47 @@ case 17: this.popState(); return 18;
457 538 break;
458 539 case 18: this.popState(); return 18;
459 540 break;
460   -case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 28;
  541 +case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29;
  542 +break;
  543 +case 20: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29;
461 544 break;
462   -case 20: return 30;
  545 +case 21: yy_.yytext = yy_.yytext.substr(1); return 27;
463 546 break;
464   -case 21: return 30;
  547 +case 22: return 31;
465 548 break;
466   -case 22: return 29;
  549 +case 23: return 31;
467 550 break;
468   -case 23: return 33;
  551 +case 24: return 30;
469 552 break;
470   -case 24: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 33;
  553 +case 25: return 34;
471 554 break;
472   -case 25: return 'INVALID';
  555 +case 26: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 34;
473 556 break;
474   -case 26: return 5;
  557 +case 27: return 'INVALID';
  558 +break;
  559 +case 28: return 5;
475 560 break;
476 561 }
477 562 };
478   -lexer.rules = [/^[^\x00]*?(?=(\{\{))/,/^[^\x00]+/,/^[^\x00]{2,}?(?=(\{\{))/,/^\{\{>/,/^\{\{#/,/^\{\{\//,/^\{\{\^/,/^\{\{\s*else\b/,/^\{\{\{/,/^\{\{&/,/^\{\{![\s\S]*?\}\}/,/^\{\{/,/^=/,/^\.(?=[} ])/,/^\.\./,/^[\/.]/,/^\s+/,/^\}\}\}/,/^\}\}/,/^"(\\["]|[^"])*"/,/^true(?=[}\s])/,/^false(?=[}\s])/,/^[0-9]+(?=[}\s])/,/^[a-zA-Z0-9_$-]+(?=[=}\s\/.])/,/^\[[^\]]*\]/,/^./,/^$/];
479   -lexer.conditions = {"mu":{"rules":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,26],"inclusive":true}};return lexer;})()
  563 +lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/];
  564 +lexer.conditions = {"mu":{"rules":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,28],"inclusive":true}};
  565 +return lexer;})()
480 566 parser.lexer = lexer;
481   -return parser;
  567 +function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;
  568 +return new Parser;
482 569 })();
483 570 if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
484 571 exports.parser = handlebars;
  572 +exports.Parser = handlebars.Parser;
485 573 exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); }
486 574 exports.main = function commonjsMain(args) {
487 575 if (!args[1])
488 576 throw new Error('Usage: '+args[0]+' FILE');
  577 + var source, cwd;
489 578 if (typeof process !== 'undefined') {
490   - var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8");
  579 + source = require('fs').readFileSync(require('path').resolve(args[1]), "utf8");
491 580 } else {
492   - var cwd = require("file").path(require("file").cwd());
493   - var source = cwd.join(args[1]).read({charset: "utf-8"});
  581 + source = require("file").path(require("file").cwd()).join(args[1]).read({charset: "utf-8"});
494 582 }
495 583 return exports.parser.parse(source);
496 584 }
@@ -531,12 +619,26 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
531 619 if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
532 620 };
533 621
534   - Handlebars.AST.MustacheNode = function(params, hash, unescaped) {
  622 + Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
535 623 this.type = "mustache";
536   - this.id = params[0];
537   - this.params = params.slice(1);
538   - this.hash = hash;
539 624 this.escaped = !unescaped;
  625 + this.hash = hash;
  626 +
  627 + var id = this.id = rawParams[0];
  628 + var params = this.params = rawParams.slice(1);
  629 +
  630 + // a mustache is an eligible helper if:
  631 + // * its id is simple (a single part, not `this` or `..`)
  632 + var eligibleHelper = this.eligibleHelper = id.isSimple;
  633 +
  634 + // a mustache is definitely a helper if:
  635 + // * it is an eligible helper, and
  636 + // * it has at least one parameter or hash segment
  637 + this.isHelper = eligibleHelper && (params.length || hash);
  638 +
  639 + // if a mustache is an eligible helper but not a definite
  640 + // helper, it is ambiguous, and will be resolved in a later
  641 + // pass or at runtime.
540 642 };
541 643
542 644 Handlebars.AST.PartialNode = function(id, context) {
@@ -554,18 +656,16 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
554 656 }
555 657 };
556 658
557   - Handlebars.AST.BlockNode = function(mustache, program, close) {
  659 + Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
558 660 verifyMatch(mustache.id, close);
559 661 this.type = "block";
560 662 this.mustache = mustache;
561 663 this.program = program;
562   - };
  664 + this.inverse = inverse;
563 665
564   - Handlebars.AST.InverseNode = function(mustache, program, close) {
565   - verifyMatch(mustache.id, close);
566   - this.type = "inverse";
567   - this.mustache = mustache;
568   - this.program = program;
  666 + if (this.inverse && !this.program) {
  667 + this.isInverse = true;
  668 + }
569 669 };
570 670
571 671 Handlebars.AST.ContentNode = function(string) {
@@ -595,7 +695,15 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
595 695 this.parts = dig;
596 696 this.string = dig.join('.');
597 697 this.depth = depth;
598   - this.isSimple = (dig.length === 1) && (depth === 0);
  698 +
  699 + // an ID is simple if it only has one part, and that part is not
  700 + // `..` or `this`.
  701 + this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
  702 + };
  703 +
  704 + Handlebars.AST.DataNode = function(id) {
  705 + this.type = "DATA";
  706 + this.id = id;
599 707 };
600 708
601 709 Handlebars.AST.StringNode = function(string) {
@@ -629,7 +737,7 @@ Handlebars.Exception = function(message) {
629 737
630 738 this.message = tmp.message;
631 739 };
632   -Handlebars.Exception.prototype = new Error;
  740 +Handlebars.Exception.prototype = new Error();
633 741
634 742 // Build out our basic SafeString type
635 743 Handlebars.SafeString = function(string) {
@@ -641,6 +749,7 @@ Handlebars.SafeString.prototype.toString = function() {
641 749
642 750 (function() {
643 751 var escape = {
  752 + "&": "&amp;",
644 753 "<": "&lt;",
645 754 ">": "&gt;",
646 755 '"': "&quot;",
@@ -648,7 +757,7 @@ Handlebars.SafeString.prototype.toString = function() {
648 757 "`": "&#x60;"
649 758 };
650 759
651   - var badChars = /&(?!\w+;)|[<>"'`]/g;
  760 + var badChars = /[&<>"'`]/g;
652 761 var possible = /[&<>"'`]/;
653 762
654 763 var escapeChar = function(chr) {
@@ -684,88 +793,38 @@ Handlebars.SafeString.prototype.toString = function() {
684 793 };
685 794 })();;
686 795 // lib/handlebars/compiler/compiler.js
  796 +
  797 +/*jshint eqnull:true*/
687 798 Handlebars.Compiler = function() {};
688 799 Handlebars.JavaScriptCompiler = function() {};
689 800
690 801 (function(Compiler, JavaScriptCompiler) {
691   - Compiler.OPCODE_MAP = {
692   - appendContent: 1,
693   - getContext: 2,
694   - lookupWithHelpers: 3,
695   - lookup: 4,
696   - append: 5,
697   - invokeMustache: 6,
698   - appendEscaped: 7,
699   - pushString: 8,
700   - truthyOrFallback: 9,
701   - functionOrFallback: 10,
702   - invokeProgram: 11,
703   - invokePartial: 12,
704   - push: 13,
705   - assignToHash: 15,
706   - pushStringParam: 16
707   - };
708   -
709   - Compiler.MULTI_PARAM_OPCODES = {
710   - appendContent: 1,
711   - getContext: 1,
712   - lookupWithHelpers: 2,
713   - lookup: 1,
714   - invokeMustache: 3,
715   - pushString: 1,
716   - truthyOrFallback: 1,
717   - functionOrFallback: 1,
718   - invokeProgram: 3,
719   - invokePartial: 1,
720   - push: 1,
721   - assignToHash: 1,
722   - pushStringParam: 1
723   - };
724   -
725   - Compiler.DISASSEMBLE_MAP = {};
726   -
727   - for(var prop in Compiler.OPCODE_MAP) {
728   - var value = Compiler.OPCODE_MAP[prop];
729   - Compiler.DISASSEMBLE_MAP[value] = prop;
730   - }
731   -
732   - Compiler.multiParamSize = function(code) {
733   - return Compiler.MULTI_PARAM_OPCODES[Compiler.DISASSEMBLE_MAP[code]];
734   - };
  802 + // the foundHelper register will disambiguate helper lookup from finding a
  803 + // function in a context. This is necessary for mustache compatibility, which
  804 + // requires that context functions in blocks are evaluated by blockHelperMissing,
  805 + // and then proceed as if the resulting value was provided to blockHelperMissing.
735 806
736 807 Compiler.prototype = {
737 808 compiler: Compiler,
738 809
739 810 disassemble: function() {
740   - var opcodes = this.opcodes, opcode, nextCode;
741   - var out = [], str, name, value;
  811 + var opcodes = this.opcodes, opcode, out = [], params, param;
742 812
743   - for(var i=0, l=opcodes.length; i<l; i++) {
  813 + for (var i=0, l=opcodes.length; i<l; i++) {
744 814 opcode = opcodes[i];
745 815
746   - if(opcode === 'DECLARE') {
747   - name = opcodes[++i];
748   - value = opcodes[++i];
749   - out.push("DECLARE " + name + " = " + value);
  816 + if (opcode.opcode === 'DECLARE') {
  817 + out.push("DECLARE " + opcode.name + "=" + opcode.value);
750 818 } else {
751   - str = Compiler.DISASSEMBLE_MAP[opcode];
752   -
753   - var extraParams = Compiler.multiParamSize(opcode);
754   - var codes = [];
755   -
756   - for(var j=0; j<extraParams; j++) {
757   - nextCode = opcodes[++i];
758   -
759   - if(typeof nextCode === "string") {
760   - nextCode = "\"" + nextCode.replace("\n", "\\n") + "\"";
  819 + params = [];
  820 + for (var j=0; j<opcode.args.length; j++) {
  821 + param = opcode.args[j];
  822 + if (typeof param === "string") {
  823 + param = "\"" + param.replace("\n", "\\n") + "\"";
761 824 }
762   -
763   - codes.push(nextCode);
  825 + params.push(param);
764 826 }
765   -
766   - str = str + " " + codes.join(" ");
767   -
768   - out.push(str);
  827 + out.push(opcode.opcode + " " + params.join(" "));
769 828 }
770 829 }
771 830
@@ -822,7 +881,7 @@ Handlebars.JavaScriptCompiler = function() {};
822 881
823 882 compileProgram: function(program) {
824 883 var result = new this.compiler().compile(program, this.options);
825   - var guid = this.guid++;
  884 + var guid = this.guid++, depth;
826 885
827 886 this.usePartial = this.usePartial || result.usePartial;
828 887
@@ -839,32 +898,42 @@ Handlebars.JavaScriptCompiler = function() {};
839 898 },
840 899
841 900 block: function(block) {
842   - var mustache = block.mustache;
843   - var depth, child, inverse, inverseGuid;
844   -
845   - var params = this.setupStackForMustache(mustache);
  901 + var mustache = block.mustache,
  902 + program = block.program,
  903 + inverse = block.inverse;
846 904
847   - var programGuid = this.compileProgram(block.program);
848   -
849   - if(block.program.inverse) {
850   - inverseGuid = this.compileProgram(block.program.inverse);
851   - this.declare('inverse', inverseGuid);
  905 + if (program) {
  906 + program = this.compileProgram(program);
852 907 }
853 908
854   - this.opcode('invokeProgram', programGuid, params.length, !!mustache.hash);
855   - this.declare('inverse', null);
856   - this.opcode('append');
857   - },
  909 + if (inverse) {
  910 + inverse = this.compileProgram(inverse);
  911 + }
858 912
859   - inverse: function(block) {
860   - var params = this.setupStackForMustache(block.mustache);
  913 + var type = this.classifyMustache(mustache);
861 914
862   - var programGuid = this.compileProgram(block.program);
  915 + if (type === "helper") {
  916 + this.helperMustache(mustache, program, inverse);
  917 + } else if (type === "simple") {
  918 + this.simpleMustache(mustache);
863 919
864   - this.declare('inverse', programGuid);
  920 + // now that the simple mustache is resolved, we need to
  921 + // evaluate it by executing `blockHelperMissing`
  922 + this.opcode('pushProgram', program);
  923 + this.opcode('pushProgram', inverse);
  924 + this.opcode('pushLiteral', '{}');
  925 + this.opcode('blockValue');
  926 + } else {
  927 + this.ambiguousMustache(mustache, program, inverse);
  928 +
  929 + // now that the simple mustache is resolved, we need to
  930 + // evaluate it by executing `blockHelperMissing`
  931 + this.opcode('pushProgram', program);
  932 + this.opcode('pushProgram', inverse);
  933 + this.opcode('pushLiteral', '{}');
  934 + this.opcode('ambiguousBlockValue');
  935 + }
865 936
866   - this.opcode('invokeProgram', null, params.length, !!block.mustache.hash);
867   - this.declare('inverse', null);
868 937 this.opcode('append');
869 938 },
870 939
@@ -901,44 +970,140 @@ Handlebars.JavaScriptCompiler = function() {};
901 970 },
902 971
903 972 mustache: function(mustache) {
904   - var params = this.setupStackForMustache(mustache);
  973 + var options = this.options;
  974 + var type = this.classifyMustache(mustache);
905 975
906   - this.opcode('invokeMustache', params.length, mustache.id.original, !!mustache.hash);
  976 + if (type === "simple") {
  977 + this.simpleMustache(mustache);
  978 + } else if (type === "helper") {
  979 + this.helperMustache(mustache);
  980 + } else {
  981 + this.ambiguousMustache(mustache);
  982 + }
907 983
908   - if(mustache.escaped && !this.options.noEscape) {
  984 + if(mustache.escaped && !options.noEscape) {
909 985 this.opcode('appendEscaped');
910 986 } else {
911 987 this.opcode('append');
912 988 }
913 989 },
914 990
  991 + ambiguousMustache: function(mustache, program, inverse) {
  992 + var id = mustache.id, name = id.parts[0];
  993 +
  994 + this.opcode('getContext', id.depth);
  995 +
  996 + this.opcode('pushProgram', program);
  997 + this.opcode('pushProgram', inverse);
  998 +
  999 + this.opcode('invokeAmbiguous', name);
  1000 + },
  1001 +
  1002 + simpleMustache: function(mustache, program, inverse) {
  1003 + var id = mustache.id;
  1004 +
  1005 + if (id.type === 'DATA') {
  1006 + this.DATA(id);
  1007 + } else if (id.parts.length) {
  1008 + this.ID(id);
  1009 + } else {
  1010 + // Simplified ID for `this`
  1011 + this.addDepth(id.depth);
  1012 + this.opcode('getContext', id.depth);
  1013 + this.opcode('pushContext');
  1014 + }
  1015 +
  1016 + this.opcode('resolvePossibleLambda');
  1017 + },
  1018 +
  1019 + helperMustache: function(mustache, program, inverse) {
  1020 + var params = this.setupFullMustacheParams(mustache, program, inverse),
  1021 + name = mustache.id.parts[0];
  1022 +
  1023 + if (this.options.knownHelpers[name]) {
  1024 + this.opcode('invokeKnownHelper', params.length, name);
  1025 + } else if (this.knownHelpersOnly) {
  1026 + throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
  1027 + } else {
  1028 + this.opcode('invokeHelper', params.length, name);
  1029 + }
  1030 + },
  1031 +
915 1032 ID: function(id) {
916 1033 this.addDepth(id.depth);
917   -
918 1034 this.opcode('getContext', id.depth);
919 1035
920   - this.opcode('lookupWithHelpers', id.parts[0] || null, id.isScoped || false);
  1036 + var name = id.parts[0];
  1037 + if (!name) {
  1038 + this.opcode('pushContext');
  1039 + } else {
  1040 + this.opcode('lookupOnContext', id.parts[0]);
  1041 + }
921 1042
922 1043 for(var i=1, l=id.parts.length; i<l; i++) {
923 1044 this.opcode('lookup', id.parts[i]);
924 1045 }
925 1046 },
926 1047
  1048 + DATA: function(data) {
  1049 + this.options.data = true;
  1050 + this.opcode('lookupData', data.id);
  1051 + },
  1052 +
927 1053 STRING: function(string) {
928 1054 this.opcode('pushString', string.string);
929 1055 },
930 1056
931 1057 INTEGER: function(integer) {
932   - this.opcode('push', integer.integer);
  1058 + this.opcode('pushLiteral', integer.integer);
933 1059 },
934 1060
935 1061 BOOLEAN: function(bool) {
936   - this.opcode('push', bool.bool);
  1062 + this.opcode('pushLiteral', bool.bool);
937 1063 },
938 1064
939 1065 comment: function() {},
940 1066
941 1067 // HELPERS
  1068 + opcode: function(name) {
  1069 + this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
  1070 + },
  1071 +
  1072 + declare: function(name, value) {
  1073 + this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
  1074 + },
  1075 +
  1076 + addDepth: function(depth) {
  1077 + if(isNaN(depth)) { throw new Error("EWOT"); }
  1078 + if(depth === 0) { return; }
  1079 +
  1080 + if(!this.depths[depth]) {
  1081 + this.depths[depth] = true;
  1082 + this.depths.list.push(depth);
  1083 + }
  1084 + },
  1085 +
  1086 + classifyMustache: function(mustache) {
  1087 + var isHelper = mustache.isHelper;
  1088 + var isEligible = mustache.eligibleHelper;
  1089 + var options = this.options;
  1090 +
  1091 + // if ambiguous, we can possibly resolve the ambiguity now
  1092 + if (isEligible && !isHelper) {
  1093 + var name = mustache.id.parts[0];
  1094 +
  1095 + if (options.knownHelpers[name]) {
  1096 + isHelper = true;
  1097 + } else if (options.knownHelpersOnly) {
  1098 + isEligible = false;
  1099 + }
  1100 + }
  1101 +
  1102 + if (isHelper) { return "helper"; }
  1103 + else if (isEligible) { return "ambiguous"; }
  1104 + else { return "simple"; }
  1105 + },
  1106 +
942 1107 pushParams: function(params) {
943 1108 var i = params.length, param;
944 1109
@@ -958,54 +1123,52 @@ Handlebars.JavaScriptCompiler = function() {};
958 1123 }
959 1124 },
960 1125
961   - opcode: function(name, val1, val2, val3) {
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   - if(val3 !== undefined) { this.opcodes.push(val3); }
966   - },
967   -
968   - declare: function(name, value) {
969   - this.opcodes.push('DECLARE');
970   - this.opcodes.push(name);
971   - this.opcodes.push(value);
972   - },
973   -
974   - addDepth: function(depth) {
975   - if(depth === 0) { return; }
  1126 + setupMustacheParams: function(mustache) {
  1127 + var params = mustache.params;
  1128 + this.pushParams(params);
976 1129
977   - if(!this.depths[depth]) {
978   - this.depths[depth] = true;
979   - this.depths.list.push(depth);
  1130 + if(mustache.hash) {
  1131 + this.hash(mustache.hash);
  1132 + } else {
  1133 + this.opcode('pushLiteral', '{}');
980 1134 }
  1135 +
  1136 + return params;
981 1137 },
982 1138
983   - setupStackForMustache: function(mustache) {
  1139 + // this will replace setupMustacheParams when we're done
  1140 + setupFullMustacheParams: function(mustache, program, inverse) {
984 1141 var params = mustache.params;
985   -
986 1142 this.pushParams(params);
987 1143
  1144 + this.opcode('pushProgram', program);
  1145 + this.opcode('pushProgram', inverse);
  1146 +
988 1147 if(mustache.hash) {
989 1148 this.hash(mustache.hash);
  1149 + } else {
  1150 + this.opcode('pushLiteral', '{}');
990 1151 }
991 1152
992   - this.ID(mustache.id);
993   -
994 1153 return params;
995 1154 }
996 1155 };
997 1156
  1157 + var Literal = function(value) {
  1158 + this.value = value;
  1159 + };
  1160 +
998 1161 JavaScriptCompiler.prototype = {
999 1162 // PUBLIC API: You can override these methods in a subclass to provide
1000 1163 // alternative compiled forms for name lookup and buffering semantics
1001 1164 nameLookup: function(parent, name, type) {
1002   - if (/^[0-9]+$/.test(name)) {
  1165 + if (/^[0-9]+$/.test(name)) {
1003 1166 return parent + "[" + name + "]";
1004 1167 } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1005   - return parent + "." + name;
1006   - }
1007   - else {
1008   - return parent + "['" + name + "']";
  1168 + return parent + "." + name;
  1169 + }
  1170 + else {
  1171 + return parent + "['" + name + "']";
1009 1172 }
1010 1173 },
1011 1174
@@ -1028,18 +1191,21 @@ Handlebars.JavaScriptCompiler = function() {};
1028 1191 this.environment = environment;
1029 1192 this.options = options || {};
1030 1193
  1194 + Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
  1195 +
1031 1196 this.name = this.environment.name;
1032 1197 this.isChild = !!context;
1033 1198 this.context = context || {
1034 1199 programs: [],
1035   - aliases: { self: 'this' },
1036   - registers: {list: []}
  1200 + aliases: { }
1037 1201 };
1038 1202
1039 1203 this.preamble();
1040 1204
1041 1205 this.stackSlot = 0;
1042 1206 this.stackVars = [];
  1207 + this.registers = { list: [] };
  1208 + this.compileStack = [];
1043 1209
1044 1210 this.compileChildren(environment, options);
1045 1211
@@ -1048,59 +1214,35 @@ Handlebars.JavaScriptCompiler = function() {};
1048 1214 this.i = 0;
1049 1215
1050 1216 for(l=opcodes.length; this.i<l; this.i++) {
1051   - opcode = this.nextOpcode(0);
  1217 + opcode = opcodes[this.i];
1052 1218
1053   - if(opcode[0] === 'DECLARE') {
1054   - this.i = this.i + 2;
1055   - this[opcode[1]] = opcode[2];
  1219 + if(opcode.opcode === 'DECLARE') {
  1220 + this[opcode.name] = opcode.value;
1056 1221 } else {
1057   - this.i = this.i + opcode[1].length;
1058   - this[opcode[0]].apply(this, opcode[1]);
  1222 + this[opcode.opcode].apply(this, opcode.args);
1059 1223 }
1060 1224 }
1061 1225
1062 1226 return this.createFunctionContext(asObject);
1063 1227 },
1064 1228
1065   - nextOpcode: function(n) {
1066   - var opcodes = this.environment.opcodes, opcode = opcodes[this.i + n], name, val;
1067   - var extraParams, codes;
1068   -
1069   - if(opcode === 'DECLARE') {
1070   - name = opcodes[this.i + 1];
1071   - val = opcodes[this.i + 2];
1072   - return ['DECLARE', name, val];
1073   - } else {
1074   - name = Compiler.DISASSEMBLE_MAP[opcode];
1075   -
1076   - extraParams = Compiler.multiParamSize(opcode);
1077   - codes = [];
1078   -
1079   - for(var j=0; j<extraParams; j++) {
1080   - codes.push(opcodes[this.i + j + 1 + n]);
1081   - }
1082   -
1083   - return [name, codes];
1084   - }
  1229 + nextOpcode: function() {
  1230 + var opcodes = this.environment.opcodes, opcode = opcodes[this.i + 1];
  1231 + return opcodes[this.i + 1];
1085 1232 },
1086 1233
1087 1234 eat: function(opcode) {
1088   - this.i = this.i + opcode.length;
  1235 + this.i = this.i + 1;
1089 1236 },
1090 1237
1091 1238 preamble: function() {
1092 1239 var out = [];
1093 1240
1094   - // this register will disambiguate helper lookup from finding a function in
1095   - // a context. This is necessary for mustache compatibility, which requires
1096   - // that context functions in blocks are evaluated by blockHelperMissing, and
1097   - // then proceed as if the resulting value was provided to blockHelperMissing.
1098   - this.useRegister('foundHelper');
1099   -
1100 1241 if (!this.isChild) {
1101 1242 var namespace = this.namespace;
1102 1243 var copies = "helpers = helpers || " + namespace + ".helpers;";
1103   - if(this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
  1244 + if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
  1245 + if (this.options.data) { copies = copies + " data = data || {};"; }
1104 1246 out.push(copies);
1105 1247 } else {
1106 1248 out.push('');
@@ -1119,10 +1261,7 @@ Handlebars.JavaScriptCompiler = function() {};
1119 1261 },
1120 1262
1121 1263 createFunctionContext: function(asObject) {
1122   - var locals = this.stackVars;
1123   - if (!this.isChild) {
1124   - locals = locals.concat(this.context.registers.list);
1125   - }
  1264 + var locals = this.stackVars.concat(this.registers.list);
1126 1265
1127 1266 if(locals.length > 0) {
1128 1267 this.source[1] = this.source[1] + ", " + locals.join(", ");
@@ -1130,7 +1269,7 @@ Handlebars.JavaScriptCompiler = function() {};
1130 1269
1131 1270 // Generate minimizer alias mappings
1132 1271 if (!this.isChild) {
1133   - var aliases = []
  1272 + var aliases = [];
1134 1273 for (var alias in this.context.aliases) {
1135 1274 this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1136 1275 }
@@ -1166,10 +1305,64 @@ Handlebars.JavaScriptCompiler = function() {};
1166 1305 }
1167 1306 },
1168 1307
  1308 + // [blockValue]
  1309 + //
  1310 + // On stack, before: hash, inverse, program, value