handlebars_assets 0.15 → 0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d256320ba8600f2735ac4006de0ef9568de10837
4
- data.tar.gz: 047bfc66136a8fde214b7f081183ff8eb9f615a5
3
+ metadata.gz: db80ec041bb1a30fa034a7191da617510877dd1a
4
+ data.tar.gz: 591a444cbb3bdb7f71ee728c085b7912bf7769ce
5
5
  SHA512:
6
- metadata.gz: fabda19de11168da2423a3aba95420a67695e0749d50c1791f3b5208b3a048b2b8006a2e6bc27959752efab09b2e5b48915d79bb7e1e2bad1dab2e35ba715c1c
7
- data.tar.gz: e8118dc25fe68a2a32d0ad80169673e7724f624ebf24677069cc6d6a6e753b14cfdf8e6299c2b5be7f21455a025c0bd1a094e9c9028e68c1dc414e63ea921010
6
+ metadata.gz: b79943a6ffe7c085e29907aeeb0ee2187710d379453cae0bbbe3dfb25aef0b61470b6e170ebb9f413a9d03d34f1f6f00984b6bc4b53592173aa53cdb262611bb
7
+ data.tar.gz: 0c91048ddb22913fccc4334d1f0a2c4d92b851b550710cb0d3660d2cd4366cda16f4a1038894b46ecf1196edfc3e709783b12c38e756cbf216706f1bd7f5f5df
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.16 (2014-05-27)
2
+
3
+ * README clarification - @jithugopal
4
+ * Upgrade `handlebars` to 1.1.3 - @neodude
5
+
1
6
  ## 0.15 (2013-12-06)
2
7
 
3
8
  * Allow use of ember and other handlebars simultaneously - @rbhitchcock
data/README.md CHANGED
@@ -136,6 +136,8 @@ If your file is `templates/contacts/new.hbs`, the asset pipeline will generate J
136
136
 
137
137
  You can then invoke the resulting template in your application's JavaScript
138
138
 
139
+ NOTE: There will be no javascript object `HandlebarsTemplates` unless at least ONE template is included.
140
+
139
141
  ```javascript
140
142
  HandlebarsTemplates['contacts/new'](context);
141
143
  ```
@@ -1,3 +1,3 @@
1
1
  module HandlebarsAssets
2
- VERSION = "0.15"
2
+ VERSION = "0.16"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
 
3
- handlebars v1.1.2
3
+ handlebars v1.3.0
4
4
 
5
5
  Copyright (C) 2011 by Yehuda Katz
6
6
 
@@ -24,6 +24,7 @@ THE SOFTWARE.
24
24
 
25
25
  @license
26
26
  */
27
+ /* exported Handlebars */
27
28
  var Handlebars = (function() {
28
29
  // handlebars/safe-string.js
29
30
  var __module4__ = (function() {
@@ -46,6 +47,7 @@ var __module4__ = (function() {
46
47
  var __module3__ = (function(__dependency1__) {
47
48
  "use strict";
48
49
  var __exports__ = {};
50
+ /*jshint -W004 */
49
51
  var SafeString = __dependency1__;
50
52
 
51
53
  var escape = {
@@ -66,7 +68,7 @@ var __module3__ = (function(__dependency1__) {
66
68
 
67
69
  function extend(obj, value) {
68
70
  for(var key in value) {
69
- if(value.hasOwnProperty(key)) {
71
+ if(Object.prototype.hasOwnProperty.call(value, key)) {
70
72
  obj[key] = value[key];
71
73
  }
72
74
  }
@@ -130,13 +132,25 @@ var __module5__ = (function() {
130
132
 
131
133
  var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
132
134
 
133
- function Exception(/* message */) {
134
- var tmp = Error.prototype.constructor.apply(this, arguments);
135
+ function Exception(message, node) {
136
+ var line;
137
+ if (node && node.firstLine) {
138
+ line = node.firstLine;
139
+
140
+ message += ' - ' + line + ':' + node.firstColumn;
141
+ }
142
+
143
+ var tmp = Error.prototype.constructor.call(this, message);
135
144
 
136
145
  // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
137
146
  for (var idx = 0; idx < errorProps.length; idx++) {
138
147
  this[errorProps[idx]] = tmp[errorProps[idx]];
139
148
  }
149
+
150
+ if (line) {
151
+ this.lineNumber = line;
152
+ this.column = node.firstColumn;
153
+ }
140
154
  }
141
155
 
142
156
  Exception.prototype = new Error();
@@ -149,11 +163,10 @@ var __module5__ = (function() {
149
163
  var __module2__ = (function(__dependency1__, __dependency2__) {
150
164
  "use strict";
151
165
  var __exports__ = {};
152
- /*globals Exception, Utils */
153
166
  var Utils = __dependency1__;
154
167
  var Exception = __dependency2__;
155
168
 
156
- var VERSION = "1.1.2";
169
+ var VERSION = "1.3.0";
157
170
  __exports__.VERSION = VERSION;var COMPILER_REVISION = 4;
158
171
  __exports__.COMPILER_REVISION = COMPILER_REVISION;
159
172
  var REVISION_CHANGES = {
@@ -205,7 +218,7 @@ var __module2__ = (function(__dependency1__, __dependency2__) {
205
218
  if(arguments.length === 2) {
206
219
  return undefined;
207
220
  } else {
208
- throw new Error("Missing helper: '" + arg + "'");
221
+ throw new Exception("Missing helper: '" + arg + "'");
209
222
  }
210
223
  });
211
224
 
@@ -244,7 +257,7 @@ var __module2__ = (function(__dependency1__, __dependency2__) {
244
257
  for(var j = context.length; i<j; i++) {
245
258
  if (data) {
246
259
  data.index = i;
247
- data.first = (i === 0)
260
+ data.first = (i === 0);
248
261
  data.last = (i === (context.length-1));
249
262
  }
250
263
  ret = ret + fn(context[i], { data: data });
@@ -252,7 +265,11 @@ var __module2__ = (function(__dependency1__, __dependency2__) {
252
265
  } else {
253
266
  for(var key in context) {
254
267
  if(context.hasOwnProperty(key)) {
255
- if(data) { data.key = key; }
268
+ if(data) {
269
+ data.key = key;
270
+ data.index = i;
271
+ data.first = (i === 0);
272
+ }
256
273
  ret = ret + fn(context[key], {data: data});
257
274
  i++;
258
275
  }
@@ -332,7 +349,6 @@ var __module2__ = (function(__dependency1__, __dependency2__) {
332
349
  var __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) {
333
350
  "use strict";
334
351
  var __exports__ = {};
335
- /*global Utils */
336
352
  var Utils = __dependency1__;
337
353
  var Exception = __dependency2__;
338
354
  var COMPILER_REVISION = __dependency3__.COMPILER_REVISION;
@@ -346,42 +362,37 @@ var __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) {
346
362
  if (compilerRevision < currentRevision) {
347
363
  var runtimeVersions = REVISION_CHANGES[currentRevision],
348
364
  compilerVersions = REVISION_CHANGES[compilerRevision];
349
- throw new Error("Template was precompiled with an older version of Handlebars than the current runtime. "+
365
+ throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+
350
366
  "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").");
351
367
  } else {
352
368
  // Use the embedded version info since the runtime doesn't know about this revision yet
353
- throw new Error("Template was precompiled with a newer version of Handlebars than the current runtime. "+
369
+ throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+
354
370
  "Please update your runtime to a newer version ("+compilerInfo[1]+").");
355
371
  }
356
372
  }
357
373
  }
358
374
 
359
- // TODO: Remove this line and break up compilePartial
375
+ __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial
360
376
 
361
377
  function template(templateSpec, env) {
362
378
  if (!env) {
363
- throw new Error("No environment passed to template");
379
+ throw new Exception("No environment passed to template");
364
380
  }
365
381
 
366
- var invokePartialWrapper;
367
- if (env.compile) {
368
- invokePartialWrapper = function(partial, name, context, helpers, partials, data) {
369
- // TODO : Check this for all inputs and the options handling (partial flag, etc). This feels
370
- // like there should be a common exec path
371
- var result = invokePartial.apply(this, arguments);
372
- if (result) { return result; }
382
+ // Note: Using env.VM references rather than local var references throughout this section to allow
383
+ // for external users to override these as psuedo-supported APIs.
384
+ var invokePartialWrapper = function(partial, name, context, helpers, partials, data) {
385
+ var result = env.VM.invokePartial.apply(this, arguments);
386
+ if (result != null) { return result; }
373
387
 
388
+ if (env.compile) {
374
389
  var options = { helpers: helpers, partials: partials, data: data };
375
390
  partials[name] = env.compile(partial, { data: data !== undefined }, env);
376
391
  return partials[name](context, options);
377
- };
378
- } else {
379
- invokePartialWrapper = function(partial, name /* , context, helpers, partials, data */) {
380
- var result = invokePartial.apply(this, arguments);
381
- if (result) { return result; }
392
+ } else {
382
393
  throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
383
- };
384
- }
394
+ }
395
+ };
385
396
 
386
397
  // Just add water
387
398
  var container = {
@@ -407,8 +418,8 @@ var __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) {
407
418
  }
408
419
  return ret;
409
420
  },
410
- programWithDepth: programWithDepth,
411
- noop: noop,
421
+ programWithDepth: env.VM.programWithDepth,
422
+ noop: env.VM.noop,
412
423
  compilerInfo: null
413
424
  };
414
425
 
@@ -430,7 +441,7 @@ var __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) {
430
441
  options.data);
431
442
 
432
443
  if (!options.partial) {
433
- checkRevision(container.compilerInfo);
444
+ env.VM.checkRevision(container.compilerInfo);
434
445
  }
435
446
 
436
447
  return result;
@@ -481,6 +492,7 @@ var __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) {
481
492
  var __module1__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {
482
493
  "use strict";
483
494
  var __exports__;
495
+ /*globals Handlebars: true */
484
496
  var base = __dependency1__;
485
497
 
486
498
  // Each of these augment the Handlebars object. No need to setup here.
@@ -517,154 +529,233 @@ var __module1__ = (function(__dependency1__, __dependency2__, __dependency3__, _
517
529
  // handlebars/compiler/ast.js
518
530
  var __module7__ = (function(__dependency1__) {
519
531
  "use strict";
520
- var __exports__ = {};
532
+ var __exports__;
521
533
  var Exception = __dependency1__;
522
534
 
523
- function ProgramNode(statements, inverseStrip, inverse) {
524
- this.type = "program";
525
- this.statements = statements;
526
- this.strip = {};
527
-
528
- if(inverse) {
529
- this.inverse = new ProgramNode(inverse, inverseStrip);
530
- this.strip.right = inverseStrip.left;
531
- } else if (inverseStrip) {
532
- this.strip.left = inverseStrip.right;
533
- }
535
+ function LocationInfo(locInfo){
536
+ locInfo = locInfo || {};
537
+ this.firstLine = locInfo.first_line;
538
+ this.firstColumn = locInfo.first_column;
539
+ this.lastColumn = locInfo.last_column;
540
+ this.lastLine = locInfo.last_line;
534
541
  }
535
542
 
536
- __exports__.ProgramNode = ProgramNode;function MustacheNode(rawParams, hash, open, strip) {
537
- this.type = "mustache";
538
- this.hash = hash;
539
- this.strip = strip;
543
+ var AST = {
544
+ ProgramNode: function(statements, inverseStrip, inverse, locInfo) {
545
+ var inverseLocationInfo, firstInverseNode;
546
+ if (arguments.length === 3) {
547
+ locInfo = inverse;
548
+ inverse = null;
549
+ } else if (arguments.length === 2) {
550
+ locInfo = inverseStrip;
551
+ inverseStrip = null;
552
+ }
553
+
554
+ LocationInfo.call(this, locInfo);
555
+ this.type = "program";
556
+ this.statements = statements;
557
+ this.strip = {};
558
+
559
+ if(inverse) {
560
+ firstInverseNode = inverse[0];
561
+ if (firstInverseNode) {
562
+ inverseLocationInfo = {
563
+ first_line: firstInverseNode.firstLine,
564
+ last_line: firstInverseNode.lastLine,
565
+ last_column: firstInverseNode.lastColumn,
566
+ first_column: firstInverseNode.firstColumn
567
+ };
568
+ this.inverse = new AST.ProgramNode(inverse, inverseStrip, inverseLocationInfo);
569
+ } else {
570
+ this.inverse = new AST.ProgramNode(inverse, inverseStrip);
571
+ }
572
+ this.strip.right = inverseStrip.left;
573
+ } else if (inverseStrip) {
574
+ this.strip.left = inverseStrip.right;
575
+ }
576
+ },
540
577
 
541
- var escapeFlag = open[3] || open[2];
542
- this.escaped = escapeFlag !== '{' && escapeFlag !== '&';
578
+ MustacheNode: function(rawParams, hash, open, strip, locInfo) {
579
+ LocationInfo.call(this, locInfo);
580
+ this.type = "mustache";
581
+ this.strip = strip;
543
582
 
544
- var id = this.id = rawParams[0];
545
- var params = this.params = rawParams.slice(1);
583
+ // Open may be a string parsed from the parser or a passed boolean flag
584
+ if (open != null && open.charAt) {
585
+ // Must use charAt to support IE pre-10
586
+ var escapeFlag = open.charAt(3) || open.charAt(2);
587
+ this.escaped = escapeFlag !== '{' && escapeFlag !== '&';
588
+ } else {
589
+ this.escaped = !!open;
590
+ }
546
591
 
547
- // a mustache is an eligible helper if:
548
- // * its id is simple (a single part, not `this` or `..`)
549
- var eligibleHelper = this.eligibleHelper = id.isSimple;
592
+ if (rawParams instanceof AST.SexprNode) {
593
+ this.sexpr = rawParams;
594
+ } else {
595
+ // Support old AST API
596
+ this.sexpr = new AST.SexprNode(rawParams, hash);
597
+ }
550
598
 
551
- // a mustache is definitely a helper if:
552
- // * it is an eligible helper, and
553
- // * it has at least one parameter or hash segment
554
- this.isHelper = eligibleHelper && (params.length || hash);
599
+ this.sexpr.isRoot = true;
555
600
 
556
- // if a mustache is an eligible helper but not a definite
557
- // helper, it is ambiguous, and will be resolved in a later
558
- // pass or at runtime.
559
- }
601
+ // Support old AST API that stored this info in MustacheNode
602
+ this.id = this.sexpr.id;
603
+ this.params = this.sexpr.params;
604
+ this.hash = this.sexpr.hash;
605
+ this.eligibleHelper = this.sexpr.eligibleHelper;
606
+ this.isHelper = this.sexpr.isHelper;
607
+ },
560
608
 
561
- __exports__.MustacheNode = MustacheNode;function PartialNode(partialName, context, strip) {
562
- this.type = "partial";
563
- this.partialName = partialName;
564
- this.context = context;
565
- this.strip = strip;
566
- }
609
+ SexprNode: function(rawParams, hash, locInfo) {
610
+ LocationInfo.call(this, locInfo);
567
611
 
568
- __exports__.PartialNode = PartialNode;function BlockNode(mustache, program, inverse, close) {
569
- if(mustache.id.original !== close.path.original) {
570
- throw new Exception(mustache.id.original + " doesn't match " + close.path.original);
571
- }
612
+ this.type = "sexpr";
613
+ this.hash = hash;
572
614
 
573
- this.type = "block";
574
- this.mustache = mustache;
575
- this.program = program;
576
- this.inverse = inverse;
615
+ var id = this.id = rawParams[0];
616
+ var params = this.params = rawParams.slice(1);
577
617
 
578
- this.strip = {
579
- left: mustache.strip.left,
580
- right: close.strip.right
581
- };
618
+ // a mustache is an eligible helper if:
619
+ // * its id is simple (a single part, not `this` or `..`)
620
+ var eligibleHelper = this.eligibleHelper = id.isSimple;
582
621
 
583
- (program || inverse).strip.left = mustache.strip.right;
584
- (inverse || program).strip.right = close.strip.left;
622
+ // a mustache is definitely a helper if:
623
+ // * it is an eligible helper, and
624
+ // * it has at least one parameter or hash segment
625
+ this.isHelper = eligibleHelper && (params.length || hash);
585
626
 
586
- if (inverse && !program) {
587
- this.isInverse = true;
588
- }
589
- }
627
+ // if a mustache is an eligible helper but not a definite
628
+ // helper, it is ambiguous, and will be resolved in a later
629
+ // pass or at runtime.
630
+ },
590
631
 
591
- __exports__.BlockNode = BlockNode;function ContentNode(string) {
592
- this.type = "content";
593
- this.string = string;
594
- }
632
+ PartialNode: function(partialName, context, strip, locInfo) {
633
+ LocationInfo.call(this, locInfo);
634
+ this.type = "partial";
635
+ this.partialName = partialName;
636
+ this.context = context;
637
+ this.strip = strip;
638
+ },
595
639
 
596
- __exports__.ContentNode = ContentNode;function HashNode(pairs) {
597
- this.type = "hash";
598
- this.pairs = pairs;
599
- }
640
+ BlockNode: function(mustache, program, inverse, close, locInfo) {
641
+ LocationInfo.call(this, locInfo);
642
+
643
+ if(mustache.sexpr.id.original !== close.path.original) {
644
+ throw new Exception(mustache.sexpr.id.original + " doesn't match " + close.path.original, this);
645
+ }
600
646
 
601
- __exports__.HashNode = HashNode;function IdNode(parts) {
602
- this.type = "ID";
647
+ this.type = 'block';
648
+ this.mustache = mustache;
649
+ this.program = program;
650
+ this.inverse = inverse;
603
651
 
604
- var original = "",
605
- dig = [],
606
- depth = 0;
652
+ this.strip = {
653
+ left: mustache.strip.left,
654
+ right: close.strip.right
655
+ };
607
656
 
608
- for(var i=0,l=parts.length; i<l; i++) {
609
- var part = parts[i].part;
610
- original += (parts[i].separator || '') + part;
657
+ (program || inverse).strip.left = mustache.strip.right;
658
+ (inverse || program).strip.right = close.strip.left;
611
659
 
612
- if (part === ".." || part === "." || part === "this") {
613
- if (dig.length > 0) { throw new Exception("Invalid path: " + original); }
614
- else if (part === "..") { depth++; }
615
- else { this.isScoped = true; }
660
+ if (inverse && !program) {
661
+ this.isInverse = true;
616
662
  }
617
- else { dig.push(part); }
618
- }
663
+ },
619
664
 
620
- this.original = original;
621
- this.parts = dig;
622
- this.string = dig.join('.');
623
- this.depth = depth;
665
+ ContentNode: function(string, locInfo) {
666
+ LocationInfo.call(this, locInfo);
667
+ this.type = "content";
668
+ this.string = string;
669
+ },
624
670
 
625
- // an ID is simple if it only has one part, and that part is not
626
- // `..` or `this`.
627
- this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
671
+ HashNode: function(pairs, locInfo) {
672
+ LocationInfo.call(this, locInfo);
673
+ this.type = "hash";
674
+ this.pairs = pairs;
675
+ },
628
676
 
629
- this.stringModeValue = this.string;
630
- }
677
+ IdNode: function(parts, locInfo) {
678
+ LocationInfo.call(this, locInfo);
679
+ this.type = "ID";
631
680
 
632
- __exports__.IdNode = IdNode;function PartialNameNode(name) {
633
- this.type = "PARTIAL_NAME";
634
- this.name = name.original;
635
- }
681
+ var original = "",
682
+ dig = [],
683
+ depth = 0;
636
684
 
637
- __exports__.PartialNameNode = PartialNameNode;function DataNode(id) {
638
- this.type = "DATA";
639
- this.id = id;
640
- }
685
+ for(var i=0,l=parts.length; i<l; i++) {
686
+ var part = parts[i].part;
687
+ original += (parts[i].separator || '') + part;
641
688
 
642
- __exports__.DataNode = DataNode;function StringNode(string) {
643
- this.type = "STRING";
644
- this.original =
645
- this.string =
646
- this.stringModeValue = string;
647
- }
689
+ if (part === ".." || part === "." || part === "this") {
690
+ if (dig.length > 0) {
691
+ throw new Exception("Invalid path: " + original, this);
692
+ } else if (part === "..") {
693
+ depth++;
694
+ } else {
695
+ this.isScoped = true;
696
+ }
697
+ } else {
698
+ dig.push(part);
699
+ }
700
+ }
648
701
 
649
- __exports__.StringNode = StringNode;function IntegerNode(integer) {
650
- this.type = "INTEGER";
651
- this.original =
652
- this.integer = integer;
653
- this.stringModeValue = Number(integer);
654
- }
702
+ this.original = original;
703
+ this.parts = dig;
704
+ this.string = dig.join('.');
705
+ this.depth = depth;
655
706
 
656
- __exports__.IntegerNode = IntegerNode;function BooleanNode(bool) {
657
- this.type = "BOOLEAN";
658
- this.bool = bool;
659
- this.stringModeValue = bool === "true";
660
- }
707
+ // an ID is simple if it only has one part, and that part is not
708
+ // `..` or `this`.
709
+ this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
661
710
 
662
- __exports__.BooleanNode = BooleanNode;function CommentNode(comment) {
663
- this.type = "comment";
664
- this.comment = comment;
665
- }
711
+ this.stringModeValue = this.string;
712
+ },
713
+
714
+ PartialNameNode: function(name, locInfo) {
715
+ LocationInfo.call(this, locInfo);
716
+ this.type = "PARTIAL_NAME";
717
+ this.name = name.original;
718
+ },
719
+
720
+ DataNode: function(id, locInfo) {
721
+ LocationInfo.call(this, locInfo);
722
+ this.type = "DATA";
723
+ this.id = id;
724
+ },
725
+
726
+ StringNode: function(string, locInfo) {
727
+ LocationInfo.call(this, locInfo);
728
+ this.type = "STRING";
729
+ this.original =
730
+ this.string =
731
+ this.stringModeValue = string;
732
+ },
733
+
734
+ IntegerNode: function(integer, locInfo) {
735
+ LocationInfo.call(this, locInfo);
736
+ this.type = "INTEGER";
737
+ this.original =
738
+ this.integer = integer;
739
+ this.stringModeValue = Number(integer);
740
+ },
741
+
742
+ BooleanNode: function(bool, locInfo) {
743
+ LocationInfo.call(this, locInfo);
744
+ this.type = "BOOLEAN";
745
+ this.bool = bool;
746
+ this.stringModeValue = bool === "true";
747
+ },
748
+
749
+ CommentNode: function(comment, locInfo) {
750
+ LocationInfo.call(this, locInfo);
751
+ this.type = "comment";
752
+ this.comment = comment;
753
+ }
754
+ };
666
755
 
667
- __exports__.CommentNode = CommentNode;
756
+ // Must be exported as an object rather than the root of the module as the jison lexer
757
+ // most modify the object to operate properly.
758
+ __exports__ = AST;
668
759
  return __exports__;
669
760
  })(__module5__);
670
761
 
@@ -672,107 +763,110 @@ var __module7__ = (function(__dependency1__) {
672
763
  var __module9__ = (function() {
673
764
  "use strict";
674
765
  var __exports__;
766
+ /* jshint ignore:start */
675
767
  /* Jison generated parser */
676
768
  var handlebars = (function(){
677
769
  var parser = {trace: function trace() { },
678
770
  yy: {},
679
- symbols_: {"error":2,"root":3,"statements":4,"EOF":5,"program":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,"CLOSE_UNESCAPED":24,"OPEN_PARTIAL":25,"partialName":26,"partial_option0":27,"inMustache_repetition0":28,"inMustache_option0":29,"dataName":30,"param":31,"STRING":32,"INTEGER":33,"BOOLEAN":34,"hash":35,"hash_repetition_plus0":36,"hashSegment":37,"ID":38,"EQUALS":39,"DATA":40,"pathSegments":41,"SEP":42,"$accept":0,"$end":1},
680
- 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:"CLOSE_UNESCAPED",25:"OPEN_PARTIAL",32:"STRING",33:"INTEGER",34:"BOOLEAN",38:"ID",39:"EQUALS",40:"DATA",42:"SEP"},
681
- productions_: [0,[3,2],[3,1],[6,2],[6,3],[6,2],[6,1],[6,1],[6,0],[4,1],[4,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,4],[7,2],[17,3],[17,1],[31,1],[31,1],[31,1],[31,1],[31,1],[35,1],[37,3],[26,1],[26,1],[26,1],[30,2],[21,1],[41,3],[41,1],[27,0],[27,1],[28,0],[28,2],[29,0],[29,1],[36,1],[36,2]],
771
+ symbols_: {"error":2,"root":3,"statements":4,"EOF":5,"program":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"sexpr":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"CLOSE_UNESCAPED":24,"OPEN_PARTIAL":25,"partialName":26,"partial_option0":27,"sexpr_repetition0":28,"sexpr_option0":29,"dataName":30,"param":31,"STRING":32,"INTEGER":33,"BOOLEAN":34,"OPEN_SEXPR":35,"CLOSE_SEXPR":36,"hash":37,"hash_repetition_plus0":38,"hashSegment":39,"ID":40,"EQUALS":41,"DATA":42,"pathSegments":43,"SEP":44,"$accept":0,"$end":1},
772
+ 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:"CLOSE_UNESCAPED",25:"OPEN_PARTIAL",32:"STRING",33:"INTEGER",34:"BOOLEAN",35:"OPEN_SEXPR",36:"CLOSE_SEXPR",40:"ID",41:"EQUALS",42:"DATA",44:"SEP"},
773
+ productions_: [0,[3,2],[3,1],[6,2],[6,3],[6,2],[6,1],[6,1],[6,0],[4,1],[4,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,4],[7,2],[17,3],[17,1],[31,1],[31,1],[31,1],[31,1],[31,1],[31,3],[37,1],[39,3],[26,1],[26,1],[26,1],[30,2],[21,1],[43,3],[43,1],[27,0],[27,1],[28,0],[28,2],[29,0],[29,1],[38,1],[38,2]],
682
774
  performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
683
775
 
684
776
  var $0 = $$.length - 1;
685
777
  switch (yystate) {
686
- case 1: return new yy.ProgramNode($$[$0-1]);
778
+ case 1: return new yy.ProgramNode($$[$0-1], this._$);
687
779
  break;
688
- case 2: return new yy.ProgramNode([]);
780
+ case 2: return new yy.ProgramNode([], this._$);
689
781
  break;
690
- case 3:this.$ = new yy.ProgramNode([], $$[$0-1], $$[$0]);
782
+ case 3:this.$ = new yy.ProgramNode([], $$[$0-1], $$[$0], this._$);
691
783
  break;
692
- case 4:this.$ = new yy.ProgramNode($$[$0-2], $$[$0-1], $$[$0]);
784
+ case 4:this.$ = new yy.ProgramNode($$[$0-2], $$[$0-1], $$[$0], this._$);
693
785
  break;
694
- case 5:this.$ = new yy.ProgramNode($$[$0-1], $$[$0], []);
786
+ case 5:this.$ = new yy.ProgramNode($$[$0-1], $$[$0], [], this._$);
695
787
  break;
696
- case 6:this.$ = new yy.ProgramNode($$[$0]);
788
+ case 6:this.$ = new yy.ProgramNode($$[$0], this._$);
697
789
  break;
698
- case 7:this.$ = new yy.ProgramNode([]);
790
+ case 7:this.$ = new yy.ProgramNode([], this._$);
699
791
  break;
700
- case 8:this.$ = new yy.ProgramNode([]);
792
+ case 8:this.$ = new yy.ProgramNode([], this._$);
701
793
  break;
702
794
  case 9:this.$ = [$$[$0]];
703
795
  break;
704
796
  case 10: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
705
797
  break;
706
- case 11:this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]);
798
+ case 11:this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0], this._$);
707
799
  break;
708
- case 12:this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]);
800
+ case 12:this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0], this._$);
709
801
  break;
710
802
  case 13:this.$ = $$[$0];
711
803
  break;
712
804
  case 14:this.$ = $$[$0];
713
805
  break;
714
- case 15:this.$ = new yy.ContentNode($$[$0]);
806
+ case 15:this.$ = new yy.ContentNode($$[$0], this._$);
715
807
  break;
716
- case 16:this.$ = new yy.CommentNode($$[$0]);
808
+ case 16:this.$ = new yy.CommentNode($$[$0], this._$);
717
809
  break;
718
- case 17:this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2], stripFlags($$[$0-2], $$[$0]));
810
+ case 17:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], stripFlags($$[$0-2], $$[$0]), this._$);
719
811
  break;
720
- case 18:this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2], stripFlags($$[$0-2], $$[$0]));
812
+ case 18:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], stripFlags($$[$0-2], $$[$0]), this._$);
721
813
  break;
722
814
  case 19:this.$ = {path: $$[$0-1], strip: stripFlags($$[$0-2], $$[$0])};
723
815
  break;
724
- case 20:this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2], stripFlags($$[$0-2], $$[$0]));
816
+ case 20:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], stripFlags($$[$0-2], $$[$0]), this._$);
725
817
  break;
726
- case 21:this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2], stripFlags($$[$0-2], $$[$0]));
818
+ case 21:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], stripFlags($$[$0-2], $$[$0]), this._$);
727
819
  break;
728
- case 22:this.$ = new yy.PartialNode($$[$0-2], $$[$0-1], stripFlags($$[$0-3], $$[$0]));
820
+ case 22:this.$ = new yy.PartialNode($$[$0-2], $$[$0-1], stripFlags($$[$0-3], $$[$0]), this._$);
729
821
  break;
730
822
  case 23:this.$ = stripFlags($$[$0-1], $$[$0]);
731
823
  break;
732
- case 24:this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]];
824
+ case 24:this.$ = new yy.SexprNode([$$[$0-2]].concat($$[$0-1]), $$[$0], this._$);
733
825
  break;
734
- case 25:this.$ = [[$$[$0]], null];
826
+ case 25:this.$ = new yy.SexprNode([$$[$0]], null, this._$);
735
827
  break;
736
828
  case 26:this.$ = $$[$0];
737
829
  break;
738
- case 27:this.$ = new yy.StringNode($$[$0]);
830
+ case 27:this.$ = new yy.StringNode($$[$0], this._$);
739
831
  break;
740
- case 28:this.$ = new yy.IntegerNode($$[$0]);
832
+ case 28:this.$ = new yy.IntegerNode($$[$0], this._$);
741
833
  break;
742
- case 29:this.$ = new yy.BooleanNode($$[$0]);
834
+ case 29:this.$ = new yy.BooleanNode($$[$0], this._$);
743
835
  break;
744
836
  case 30:this.$ = $$[$0];
745
837
  break;
746
- case 31:this.$ = new yy.HashNode($$[$0]);
838
+ case 31:$$[$0-1].isHelper = true; this.$ = $$[$0-1];
747
839
  break;
748
- case 32:this.$ = [$$[$0-2], $$[$0]];
840
+ case 32:this.$ = new yy.HashNode($$[$0], this._$);
749
841
  break;
750
- case 33:this.$ = new yy.PartialNameNode($$[$0]);
842
+ case 33:this.$ = [$$[$0-2], $$[$0]];
751
843
  break;
752
- case 34:this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0]));
844
+ case 34:this.$ = new yy.PartialNameNode($$[$0], this._$);
753
845
  break;
754
- case 35:this.$ = new yy.PartialNameNode(new yy.IntegerNode($$[$0]));
846
+ case 35:this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0], this._$), this._$);
755
847
  break;
756
- case 36:this.$ = new yy.DataNode($$[$0]);
848
+ case 36:this.$ = new yy.PartialNameNode(new yy.IntegerNode($$[$0], this._$));
757
849
  break;
758
- case 37:this.$ = new yy.IdNode($$[$0]);
850
+ case 37:this.$ = new yy.DataNode($$[$0], this._$);
759
851
  break;
760
- case 38: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2];
852
+ case 38:this.$ = new yy.IdNode($$[$0], this._$);
761
853
  break;
762
- case 39:this.$ = [{part: $$[$0]}];
854
+ case 39: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2];
763
855
  break;
764
- case 42:this.$ = [];
856
+ case 40:this.$ = [{part: $$[$0]}];
765
857
  break;
766
- case 43:$$[$0-1].push($$[$0]);
858
+ case 43:this.$ = [];
767
859
  break;
768
- case 46:this.$ = [$$[$0]];
860
+ case 44:$$[$0-1].push($$[$0]);
769
861
  break;
770
- case 47:$$[$0-1].push($$[$0]);
862
+ case 47:this.$ = [$$[$0]];
863
+ break;
864
+ case 48:$$[$0-1].push($$[$0]);
771
865
  break;
772
866
  }
773
867
  },
774
- table: [{3:1,4:2,5:[1,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],25:[1,15]},{1:[3]},{5:[1,16],8:17,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],25:[1,15]},{1:[2,2]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],25:[2,9]},{4:20,6:18,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{4:20,6:22,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{5:[2,13],14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],25:[2,13]},{5:[2,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],25:[2,14]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],25:[2,15]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],25:[2,16]},{17:23,21:24,30:25,38:[1,28],40:[1,27],41:26},{17:29,21:24,30:25,38:[1,28],40:[1,27],41:26},{17:30,21:24,30:25,38:[1,28],40:[1,27],41:26},{17:31,21:24,30:25,38:[1,28],40:[1,27],41:26},{21:33,26:32,32:[1,34],33:[1,35],38:[1,28],41:26},{1:[2,1]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],25:[2,10]},{10:36,20:[1,37]},{4:38,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,7],22:[1,13],23:[1,14],25:[1,15]},{7:39,8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,6],22:[1,13],23:[1,14],25:[1,15]},{17:23,18:[1,40],21:24,30:25,38:[1,28],40:[1,27],41:26},{10:41,20:[1,37]},{18:[1,42]},{18:[2,42],24:[2,42],28:43,32:[2,42],33:[2,42],34:[2,42],38:[2,42],40:[2,42]},{18:[2,25],24:[2,25]},{18:[2,37],24:[2,37],32:[2,37],33:[2,37],34:[2,37],38:[2,37],40:[2,37],42:[1,44]},{21:45,38:[1,28],41:26},{18:[2,39],24:[2,39],32:[2,39],33:[2,39],34:[2,39],38:[2,39],40:[2,39],42:[2,39]},{18:[1,46]},{18:[1,47]},{24:[1,48]},{18:[2,40],21:50,27:49,38:[1,28],41:26},{18:[2,33],38:[2,33]},{18:[2,34],38:[2,34]},{18:[2,35],38:[2,35]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],25:[2,11]},{21:51,38:[1,28],41:26},{8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,3],22:[1,13],23:[1,14],25:[1,15]},{4:52,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,5],22:[1,13],23:[1,14],25:[1,15]},{14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],25:[2,23]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],25:[2,12]},{14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],25:[2,18]},{18:[2,44],21:56,24:[2,44],29:53,30:60,31:54,32:[1,57],33:[1,58],34:[1,59],35:55,36:61,37:62,38:[1,63],40:[1,27],41:26},{38:[1,64]},{18:[2,36],24:[2,36],32:[2,36],33:[2,36],34:[2,36],38:[2,36],40:[2,36]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],25:[2,17]},{5:[2,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],25:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],25:[2,21]},{18:[1,65]},{18:[2,41]},{18:[1,66]},{8:17,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],25:[1,15]},{18:[2,24],24:[2,24]},{18:[2,43],24:[2,43],32:[2,43],33:[2,43],34:[2,43],38:[2,43],40:[2,43]},{18:[2,45],24:[2,45]},{18:[2,26],24:[2,26],32:[2,26],33:[2,26],34:[2,26],38:[2,26],40:[2,26]},{18:[2,27],24:[2,27],32:[2,27],33:[2,27],34:[2,27],38:[2,27],40:[2,27]},{18:[2,28],24:[2,28],32:[2,28],33:[2,28],34:[2,28],38:[2,28],40:[2,28]},{18:[2,29],24:[2,29],32:[2,29],33:[2,29],34:[2,29],38:[2,29],40:[2,29]},{18:[2,30],24:[2,30],32:[2,30],33:[2,30],34:[2,30],38:[2,30],40:[2,30]},{18:[2,31],24:[2,31],37:67,38:[1,68]},{18:[2,46],24:[2,46],38:[2,46]},{18:[2,39],24:[2,39],32:[2,39],33:[2,39],34:[2,39],38:[2,39],39:[1,69],40:[2,39],42:[2,39]},{18:[2,38],24:[2,38],32:[2,38],33:[2,38],34:[2,38],38:[2,38],40:[2,38],42:[2,38]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],25:[2,22]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],25:[2,19]},{18:[2,47],24:[2,47],38:[2,47]},{39:[1,69]},{21:56,30:60,31:70,32:[1,57],33:[1,58],34:[1,59],38:[1,28],40:[1,27],41:26},{18:[2,32],24:[2,32],38:[2,32]}],
775
- defaultActions: {3:[2,2],16:[2,1],50:[2,41]},
868
+ table: [{3:1,4:2,5:[1,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],25:[1,15]},{1:[3]},{5:[1,16],8:17,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],25:[1,15]},{1:[2,2]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],25:[2,9]},{4:20,6:18,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{4:20,6:22,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{5:[2,13],14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],25:[2,13]},{5:[2,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],25:[2,14]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],25:[2,15]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],25:[2,16]},{17:23,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:29,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:30,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:31,21:24,30:25,40:[1,28],42:[1,27],43:26},{21:33,26:32,32:[1,34],33:[1,35],40:[1,28],43:26},{1:[2,1]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],25:[2,10]},{10:36,20:[1,37]},{4:38,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,7],22:[1,13],23:[1,14],25:[1,15]},{7:39,8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,6],22:[1,13],23:[1,14],25:[1,15]},{17:23,18:[1,40],21:24,30:25,40:[1,28],42:[1,27],43:26},{10:41,20:[1,37]},{18:[1,42]},{18:[2,43],24:[2,43],28:43,32:[2,43],33:[2,43],34:[2,43],35:[2,43],36:[2,43],40:[2,43],42:[2,43]},{18:[2,25],24:[2,25],36:[2,25]},{18:[2,38],24:[2,38],32:[2,38],33:[2,38],34:[2,38],35:[2,38],36:[2,38],40:[2,38],42:[2,38],44:[1,44]},{21:45,40:[1,28],43:26},{18:[2,40],24:[2,40],32:[2,40],33:[2,40],34:[2,40],35:[2,40],36:[2,40],40:[2,40],42:[2,40],44:[2,40]},{18:[1,46]},{18:[1,47]},{24:[1,48]},{18:[2,41],21:50,27:49,40:[1,28],43:26},{18:[2,34],40:[2,34]},{18:[2,35],40:[2,35]},{18:[2,36],40:[2,36]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],25:[2,11]},{21:51,40:[1,28],43:26},{8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,3],22:[1,13],23:[1,14],25:[1,15]},{4:52,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,5],22:[1,13],23:[1,14],25:[1,15]},{14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],25:[2,23]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],25:[2,12]},{14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],25:[2,18]},{18:[2,45],21:56,24:[2,45],29:53,30:60,31:54,32:[1,57],33:[1,58],34:[1,59],35:[1,61],36:[2,45],37:55,38:62,39:63,40:[1,64],42:[1,27],43:26},{40:[1,65]},{18:[2,37],24:[2,37],32:[2,37],33:[2,37],34:[2,37],35:[2,37],36:[2,37],40:[2,37],42:[2,37]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],25:[2,17]},{5:[2,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],25:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],25:[2,21]},{18:[1,66]},{18:[2,42]},{18:[1,67]},{8:17,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],25:[1,15]},{18:[2,24],24:[2,24],36:[2,24]},{18:[2,44],24:[2,44],32:[2,44],33:[2,44],34:[2,44],35:[2,44],36:[2,44],40:[2,44],42:[2,44]},{18:[2,46],24:[2,46],36:[2,46]},{18:[2,26],24:[2,26],32:[2,26],33:[2,26],34:[2,26],35:[2,26],36:[2,26],40:[2,26],42:[2,26]},{18:[2,27],24:[2,27],32:[2,27],33:[2,27],34:[2,27],35:[2,27],36:[2,27],40:[2,27],42:[2,27]},{18:[2,28],24:[2,28],32:[2,28],33:[2,28],34:[2,28],35:[2,28],36:[2,28],40:[2,28],42:[2,28]},{18:[2,29],24:[2,29],32:[2,29],33:[2,29],34:[2,29],35:[2,29],36:[2,29],40:[2,29],42:[2,29]},{18:[2,30],24:[2,30],32:[2,30],33:[2,30],34:[2,30],35:[2,30],36:[2,30],40:[2,30],42:[2,30]},{17:68,21:24,30:25,40:[1,28],42:[1,27],43:26},{18:[2,32],24:[2,32],36:[2,32],39:69,40:[1,70]},{18:[2,47],24:[2,47],36:[2,47],40:[2,47]},{18:[2,40],24:[2,40],32:[2,40],33:[2,40],34:[2,40],35:[2,40],36:[2,40],40:[2,40],41:[1,71],42:[2,40],44:[2,40]},{18:[2,39],24:[2,39],32:[2,39],33:[2,39],34:[2,39],35:[2,39],36:[2,39],40:[2,39],42:[2,39],44:[2,39]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],25:[2,22]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],25:[2,19]},{36:[1,72]},{18:[2,48],24:[2,48],36:[2,48],40:[2,48]},{41:[1,71]},{21:56,30:60,31:73,32:[1,57],33:[1,58],34:[1,59],35:[1,61],40:[1,28],42:[1,27],43:26},{18:[2,31],24:[2,31],32:[2,31],33:[2,31],34:[2,31],35:[2,31],36:[2,31],40:[2,31],42:[2,31]},{18:[2,33],24:[2,33],36:[2,33],40:[2,33]}],
869
+ defaultActions: {3:[2,2],16:[2,1],50:[2,42]},
776
870
  parseError: function parseError(str, hash) {
777
871
  throw new Error(str);
778
872
  },
@@ -884,8 +978,8 @@ var __module9__ = (function() {
884
978
 
885
979
  function stripFlags(open, close) {
886
980
  return {
887
- left: open[2] === '~',
888
- right: close[0] === '~' || close[1] === '~'
981
+ left: open.charAt(2) === '~',
982
+ right: close.charAt(0) === '~' || close.charAt(1) === '~'
889
983
  };
890
984
  }
891
985
 
@@ -1084,76 +1178,80 @@ var __module9__ = (function() {
1084
1178
  case 1:return 14;
1085
1179
  break;
1086
1180
  case 2:
1087
- if(yy_.yytext.slice(-1) !== "\\") this.popState();
1088
- if(yy_.yytext.slice(-1) === "\\") strip(0,1);
1181
+ this.popState();
1089
1182
  return 14;
1090
1183
 
1091
1184
  break;
1092
1185
  case 3:strip(0,4); this.popState(); return 15;
1093
1186
  break;
1094
- case 4:return 25;
1187
+ case 4:return 35;
1188
+ break;
1189
+ case 5:return 36;
1095
1190
  break;
1096
- case 5:return 16;
1191
+ case 6:return 25;
1097
1192
  break;
1098
- case 6:return 20;
1193
+ case 7:return 16;
1099
1194
  break;
1100
- case 7:return 19;
1195
+ case 8:return 20;
1101
1196
  break;
1102
- case 8:return 19;
1197
+ case 9:return 19;
1103
1198
  break;
1104
- case 9:return 23;
1199
+ case 10:return 19;
1105
1200
  break;
1106
- case 10:return 22;
1201
+ case 11:return 23;
1107
1202
  break;
1108
- case 11:this.popState(); this.begin('com');
1203
+ case 12:return 22;
1109
1204
  break;
1110
- case 12:strip(3,5); this.popState(); return 15;
1205
+ case 13:this.popState(); this.begin('com');
1111
1206
  break;
1112
- case 13:return 22;
1207
+ case 14:strip(3,5); this.popState(); return 15;
1113
1208
  break;
1114
- case 14:return 39;
1209
+ case 15:return 22;
1115
1210
  break;
1116
- case 15:return 38;
1211
+ case 16:return 41;
1117
1212
  break;
1118
- case 16:return 38;
1213
+ case 17:return 40;
1119
1214
  break;
1120
- case 17:return 42;
1215
+ case 18:return 40;
1121
1216
  break;
1122
- case 18:/*ignore whitespace*/
1217
+ case 19:return 44;
1123
1218
  break;
1124
- case 19:this.popState(); return 24;
1219
+ case 20:// ignore whitespace
1125
1220
  break;
1126
- case 20:this.popState(); return 18;
1221
+ case 21:this.popState(); return 24;
1127
1222
  break;
1128
- case 21:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 32;
1223
+ case 22:this.popState(); return 18;
1129
1224
  break;
1130
- case 22:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 32;
1225
+ case 23:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 32;
1131
1226
  break;
1132
- case 23:return 40;
1227
+ case 24:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 32;
1133
1228
  break;
1134
- case 24:return 34;
1229
+ case 25:return 42;
1135
1230
  break;
1136
- case 25:return 34;
1231
+ case 26:return 34;
1137
1232
  break;
1138
- case 26:return 33;
1233
+ case 27:return 34;
1139
1234
  break;
1140
- case 27:return 38;
1235
+ case 28:return 33;
1141
1236
  break;
1142
- case 28:yy_.yytext = strip(1,2); return 38;
1237
+ case 29:return 40;
1143
1238
  break;
1144
- case 29:return 'INVALID';
1239
+ case 30:yy_.yytext = strip(1,2); return 40;
1145
1240
  break;
1146
- case 30:return 5;
1241
+ case 31:return 'INVALID';
1242
+ break;
1243
+ case 32:return 5;
1147
1244
  break;
1148
1245
  }
1149
1246
  };
1150
- lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s])))/,/^(?:false(?=([~}\s])))/,/^(?:-?[0-9]+(?=([~}\s])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/];
1151
- lexer.conditions = {"mu":{"rules":[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,29,30],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"INITIAL":{"rules":[0,1,30],"inclusive":true}};
1247
+ lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/];
1248
+ lexer.conditions = {"mu":{"rules":[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,29,30,31,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"INITIAL":{"rules":[0,1,32],"inclusive":true}};
1152
1249
  return lexer;})()
1153
1250
  parser.lexer = lexer;
1154
1251
  function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;
1155
1252
  return new Parser;
1156
1253
  })();__exports__ = handlebars;
1254
+ /* jshint ignore:end */
1157
1255
  return __exports__;
1158
1256
  })();
1159
1257
 
@@ -1178,1383 +1276,1434 @@ var __module8__ = (function(__dependency1__, __dependency2__) {
1178
1276
  return __exports__;
1179
1277
  })(__module9__, __module7__);
1180
1278
 
1181
- // handlebars/compiler/javascript-compiler.js
1182
- var __module11__ = (function(__dependency1__) {
1279
+ // handlebars/compiler/compiler.js
1280
+ var __module10__ = (function(__dependency1__) {
1183
1281
  "use strict";
1184
- var __exports__;
1185
- var COMPILER_REVISION = __dependency1__.COMPILER_REVISION;
1186
- var REVISION_CHANGES = __dependency1__.REVISION_CHANGES;
1187
- var log = __dependency1__.log;
1282
+ var __exports__ = {};
1283
+ var Exception = __dependency1__;
1188
1284
 
1189
- function Literal(value) {
1190
- this.value = value;
1191
- }
1285
+ function Compiler() {}
1192
1286
 
1193
- function JavaScriptCompiler() {}
1287
+ __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a
1288
+ // function in a context. This is necessary for mustache compatibility, which
1289
+ // requires that context functions in blocks are evaluated by blockHelperMissing,
1290
+ // and then proceed as if the resulting value was provided to blockHelperMissing.
1194
1291
 
1195
- JavaScriptCompiler.prototype = {
1196
- // PUBLIC API: You can override these methods in a subclass to provide
1197
- // alternative compiled forms for name lookup and buffering semantics
1198
- nameLookup: function(parent, name /* , type*/) {
1199
- var wrap,
1200
- ret;
1201
- if (parent.indexOf('depth') === 0) {
1202
- wrap = true;
1203
- }
1292
+ Compiler.prototype = {
1293
+ compiler: Compiler,
1204
1294
 
1205
- if (/^[0-9]+$/.test(name)) {
1206
- ret = parent + "[" + name + "]";
1207
- } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1208
- ret = parent + "." + name;
1295
+ disassemble: function() {
1296
+ var opcodes = this.opcodes, opcode, out = [], params, param;
1297
+
1298
+ for (var i=0, l=opcodes.length; i<l; i++) {
1299
+ opcode = opcodes[i];
1300
+
1301
+ if (opcode.opcode === 'DECLARE') {
1302
+ out.push("DECLARE " + opcode.name + "=" + opcode.value);
1303
+ } else {
1304
+ params = [];
1305
+ for (var j=0; j<opcode.args.length; j++) {
1306
+ param = opcode.args[j];
1307
+ if (typeof param === "string") {
1308
+ param = "\"" + param.replace("\n", "\\n") + "\"";
1309
+ }
1310
+ params.push(param);
1311
+ }
1312
+ out.push(opcode.opcode + " " + params.join(" "));
1313
+ }
1209
1314
  }
1210
- else {
1211
- ret = parent + "['" + name + "']";
1315
+
1316
+ return out.join("\n");
1317
+ },
1318
+
1319
+ equals: function(other) {
1320
+ var len = this.opcodes.length;
1321
+ if (other.opcodes.length !== len) {
1322
+ return false;
1212
1323
  }
1213
1324
 
1214
- if (wrap) {
1215
- return '(' + parent + ' && ' + ret + ')';
1216
- } else {
1217
- return ret;
1325
+ for (var i = 0; i < len; i++) {
1326
+ var opcode = this.opcodes[i],
1327
+ otherOpcode = other.opcodes[i];
1328
+ if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
1329
+ return false;
1330
+ }
1331
+ for (var j = 0; j < opcode.args.length; j++) {
1332
+ if (opcode.args[j] !== otherOpcode.args[j]) {
1333
+ return false;
1334
+ }
1335
+ }
1218
1336
  }
1219
- },
1220
1337
 
1221
- appendToBuffer: function(string) {
1222
- if (this.environment.isSimple) {
1223
- return "return " + string + ";";
1224
- } else {
1225
- return {
1226
- appendToBuffer: true,
1227
- content: string,
1228
- toString: function() { return "buffer += " + string + ";"; }
1229
- };
1338
+ len = this.children.length;
1339
+ if (other.children.length !== len) {
1340
+ return false;
1341
+ }
1342
+ for (i = 0; i < len; i++) {
1343
+ if (!this.children[i].equals(other.children[i])) {
1344
+ return false;
1345
+ }
1230
1346
  }
1231
- },
1232
1347
 
1233
- initializeBuffer: function() {
1234
- return this.quotedString("");
1348
+ return true;
1235
1349
  },
1236
1350
 
1237
- namespace: "Handlebars",
1238
- // END PUBLIC API
1239
-
1240
- compile: function(environment, options, context, asObject) {
1241
- this.environment = environment;
1242
- this.options = options || {};
1351
+ guid: 0,
1243
1352
 
1244
- log('debug', this.environment.disassemble() + "\n\n");
1353
+ compile: function(program, options) {
1354
+ this.opcodes = [];
1355
+ this.children = [];
1356
+ this.depths = {list: []};
1357
+ this.options = options;
1245
1358
 
1246
- this.name = this.environment.name;
1247
- this.isChild = !!context;
1248
- this.context = context || {
1249
- programs: [],
1250
- environments: [],
1251
- aliases: { }
1359
+ // These changes will propagate to the other compiler components
1360
+ var knownHelpers = this.options.knownHelpers;
1361
+ this.options.knownHelpers = {
1362
+ 'helperMissing': true,
1363
+ 'blockHelperMissing': true,
1364
+ 'each': true,
1365
+ 'if': true,
1366
+ 'unless': true,
1367
+ 'with': true,
1368
+ 'log': true
1252
1369
  };
1370
+ if (knownHelpers) {
1371
+ for (var name in knownHelpers) {
1372
+ this.options.knownHelpers[name] = knownHelpers[name];
1373
+ }
1374
+ }
1253
1375
 
1254
- this.preamble();
1255
-
1256
- this.stackSlot = 0;
1257
- this.stackVars = [];
1258
- this.registers = { list: [] };
1259
- this.compileStack = [];
1260
- this.inlineStack = [];
1376
+ return this.accept(program);
1377
+ },
1261
1378
 
1262
- this.compileChildren(environment, options);
1379
+ accept: function(node) {
1380
+ var strip = node.strip || {},
1381
+ ret;
1382
+ if (strip.left) {
1383
+ this.opcode('strip');
1384
+ }
1263
1385
 
1264
- var opcodes = environment.opcodes, opcode;
1386
+ ret = this[node.type](node);
1265
1387
 
1266
- this.i = 0;
1388
+ if (strip.right) {
1389
+ this.opcode('strip');
1390
+ }
1267
1391
 
1268
- for(var l=opcodes.length; this.i<l; this.i++) {
1269
- opcode = opcodes[this.i];
1392
+ return ret;
1393
+ },
1270
1394
 
1271
- if(opcode.opcode === 'DECLARE') {
1272
- this[opcode.name] = opcode.value;
1273
- } else {
1274
- this[opcode.opcode].apply(this, opcode.args);
1275
- }
1395
+ program: function(program) {
1396
+ var statements = program.statements;
1276
1397
 
1277
- // Reset the stripNext flag if it was not set by this operation.
1278
- if (opcode.opcode !== this.stripNext) {
1279
- this.stripNext = false;
1280
- }
1398
+ for(var i=0, l=statements.length; i<l; i++) {
1399
+ this.accept(statements[i]);
1281
1400
  }
1401
+ this.isSimple = l === 1;
1282
1402
 
1283
- // Flush any trailing content that might be pending.
1284
- this.pushSource('');
1403
+ this.depths.list = this.depths.list.sort(function(a, b) {
1404
+ return a - b;
1405
+ });
1285
1406
 
1286
- return this.createFunctionContext(asObject);
1407
+ return this;
1287
1408
  },
1288
1409
 
1289
- preamble: function() {
1290
- var out = [];
1291
-
1292
- if (!this.isChild) {
1293
- var namespace = this.namespace;
1410
+ compileProgram: function(program) {
1411
+ var result = new this.compiler().compile(program, this.options);
1412
+ var guid = this.guid++, depth;
1294
1413
 
1295
- var copies = "helpers = this.merge(helpers, " + namespace + ".helpers);";
1296
- if (this.environment.usePartial) { copies = copies + " partials = this.merge(partials, " + namespace + ".partials);"; }
1297
- if (this.options.data) { copies = copies + " data = data || {};"; }
1298
- out.push(copies);
1299
- } else {
1300
- out.push('');
1301
- }
1414
+ this.usePartial = this.usePartial || result.usePartial;
1302
1415
 
1303
- if (!this.environment.isSimple) {
1304
- out.push(", buffer = " + this.initializeBuffer());
1305
- } else {
1306
- out.push("");
1416
+ this.children[guid] = result;
1417
+
1418
+ for(var i=0, l=result.depths.list.length; i<l; i++) {
1419
+ depth = result.depths.list[i];
1420
+
1421
+ if(depth < 2) { continue; }
1422
+ else { this.addDepth(depth - 1); }
1307
1423
  }
1308
1424
 
1309
- // track the last context pushed into place to allow skipping the
1310
- // getContext opcode when it would be a noop
1311
- this.lastContext = 0;
1312
- this.source = out;
1425
+ return guid;
1313
1426
  },
1314
1427
 
1315
- createFunctionContext: function(asObject) {
1316
- var locals = this.stackVars.concat(this.registers.list);
1428
+ block: function(block) {
1429
+ var mustache = block.mustache,
1430
+ program = block.program,
1431
+ inverse = block.inverse;
1317
1432
 
1318
- if(locals.length > 0) {
1319
- this.source[1] = this.source[1] + ", " + locals.join(", ");
1433
+ if (program) {
1434
+ program = this.compileProgram(program);
1320
1435
  }
1321
1436
 
1322
- // Generate minimizer alias mappings
1323
- if (!this.isChild) {
1324
- for (var alias in this.context.aliases) {
1325
- if (this.context.aliases.hasOwnProperty(alias)) {
1326
- this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1327
- }
1328
- }
1437
+ if (inverse) {
1438
+ inverse = this.compileProgram(inverse);
1329
1439
  }
1330
1440
 
1331
- if (this.source[1]) {
1332
- this.source[1] = "var " + this.source[1].substring(2) + ";";
1333
- }
1441
+ var sexpr = mustache.sexpr;
1442
+ var type = this.classifySexpr(sexpr);
1334
1443
 
1335
- // Merge children
1336
- if (!this.isChild) {
1337
- this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1338
- }
1444
+ if (type === "helper") {
1445
+ this.helperSexpr(sexpr, program, inverse);
1446
+ } else if (type === "simple") {
1447
+ this.simpleSexpr(sexpr);
1339
1448
 
1340
- if (!this.environment.isSimple) {
1341
- this.pushSource("return buffer;");
1449
+ // now that the simple mustache is resolved, we need to
1450
+ // evaluate it by executing `blockHelperMissing`
1451
+ this.opcode('pushProgram', program);
1452
+ this.opcode('pushProgram', inverse);
1453
+ this.opcode('emptyHash');
1454
+ this.opcode('blockValue');
1455
+ } else {
1456
+ this.ambiguousSexpr(sexpr, program, inverse);
1457
+
1458
+ // now that the simple mustache is resolved, we need to
1459
+ // evaluate it by executing `blockHelperMissing`
1460
+ this.opcode('pushProgram', program);
1461
+ this.opcode('pushProgram', inverse);
1462
+ this.opcode('emptyHash');
1463
+ this.opcode('ambiguousBlockValue');
1342
1464
  }
1343
1465
 
1344
- var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1466
+ this.opcode('append');
1467
+ },
1345
1468
 
1346
- for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1347
- params.push("depth" + this.environment.depths.list[i]);
1348
- }
1469
+ hash: function(hash) {
1470
+ var pairs = hash.pairs, pair, val;
1349
1471
 
1350
- // Perform a second pass over the output to merge content when possible
1351
- var source = this.mergeSource();
1472
+ this.opcode('pushHash');
1352
1473
 
1353
- if (!this.isChild) {
1354
- var revision = COMPILER_REVISION,
1355
- versions = REVISION_CHANGES[revision];
1356
- source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
1357
- }
1474
+ for(var i=0, l=pairs.length; i<l; i++) {
1475
+ pair = pairs[i];
1476
+ val = pair[1];
1358
1477
 
1359
- if (asObject) {
1360
- params.push(source);
1478
+ if (this.options.stringParams) {
1479
+ if(val.depth) {
1480
+ this.addDepth(val.depth);
1481
+ }
1482
+ this.opcode('getContext', val.depth || 0);
1483
+ this.opcode('pushStringParam', val.stringModeValue, val.type);
1361
1484
 
1362
- return Function.apply(this, params);
1363
- } else {
1364
- var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
1365
- log('debug', functionSource + "\n\n");
1366
- return functionSource;
1367
- }
1368
- },
1369
- mergeSource: function() {
1370
- // WARN: We are not handling the case where buffer is still populated as the source should
1371
- // not have buffer append operations as their final action.
1372
- var source = '',
1373
- buffer;
1374
- for (var i = 0, len = this.source.length; i < len; i++) {
1375
- var line = this.source[i];
1376
- if (line.appendToBuffer) {
1377
- if (buffer) {
1378
- buffer = buffer + '\n + ' + line.content;
1379
- } else {
1380
- buffer = line.content;
1485
+ if (val.type === 'sexpr') {
1486
+ // Subexpressions get evaluated and passed in
1487
+ // in string params mode.
1488
+ this.sexpr(val);
1381
1489
  }
1382
1490
  } else {
1383
- if (buffer) {
1384
- source += 'buffer += ' + buffer + ';\n ';
1385
- buffer = undefined;
1386
- }
1387
- source += line + '\n ';
1491
+ this.accept(val);
1388
1492
  }
1493
+
1494
+ this.opcode('assignToHash', pair[0]);
1389
1495
  }
1390
- return source;
1496
+ this.opcode('popHash');
1391
1497
  },
1392
1498
 
1393
- // [blockValue]
1394
- //
1395
- // On stack, before: hash, inverse, program, value
1396
- // On stack, after: return value of blockHelperMissing
1397
- //
1398
- // The purpose of this opcode is to take a block of the form
1399
- // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
1400
- // replace it on the stack with the result of properly
1401
- // invoking blockHelperMissing.
1402
- blockValue: function() {
1403
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1499
+ partial: function(partial) {
1500
+ var partialName = partial.partialName;
1501
+ this.usePartial = true;
1404
1502
 
1405
- var params = ["depth0"];
1406
- this.setupParams(0, params);
1503
+ if(partial.context) {
1504
+ this.ID(partial.context);
1505
+ } else {
1506
+ this.opcode('push', 'depth0');
1507
+ }
1407
1508
 
1408
- this.replaceStack(function(current) {
1409
- params.splice(1, 0, current);
1410
- return "blockHelperMissing.call(" + params.join(", ") + ")";
1411
- });
1509
+ this.opcode('invokePartial', partialName.name);
1510
+ this.opcode('append');
1412
1511
  },
1413
1512
 
1414
- // [ambiguousBlockValue]
1415
- //
1416
- // On stack, before: hash, inverse, program, value
1417
- // Compiler value, before: lastHelper=value of last found helper, if any
1418
- // On stack, after, if no lastHelper: same as [blockValue]
1419
- // On stack, after, if lastHelper: value
1420
- ambiguousBlockValue: function() {
1421
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1513
+ content: function(content) {
1514
+ this.opcode('appendContent', content.string);
1515
+ },
1422
1516
 
1423
- var params = ["depth0"];
1424
- this.setupParams(0, params);
1517
+ mustache: function(mustache) {
1518
+ this.sexpr(mustache.sexpr);
1425
1519
 
1426
- var current = this.topStack();
1427
- params.splice(1, 0, current);
1520
+ if(mustache.escaped && !this.options.noEscape) {
1521
+ this.opcode('appendEscaped');
1522
+ } else {
1523
+ this.opcode('append');
1524
+ }
1525
+ },
1428
1526
 
1429
- // Use the options value generated from the invocation
1430
- params[params.length-1] = 'options';
1527
+ ambiguousSexpr: function(sexpr, program, inverse) {
1528
+ var id = sexpr.id,
1529
+ name = id.parts[0],
1530
+ isBlock = program != null || inverse != null;
1431
1531
 
1432
- this.pushSource("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
1433
- },
1532
+ this.opcode('getContext', id.depth);
1434
1533
 
1435
- // [appendContent]
1436
- //
1437
- // On stack, before: ...
1438
- // On stack, after: ...
1439
- //
1440
- // Appends the string value of `content` to the current buffer
1441
- appendContent: function(content) {
1442
- if (this.pendingContent) {
1443
- content = this.pendingContent + content;
1444
- }
1445
- if (this.stripNext) {
1446
- content = content.replace(/^\s+/, '');
1447
- }
1534
+ this.opcode('pushProgram', program);
1535
+ this.opcode('pushProgram', inverse);
1448
1536
 
1449
- this.pendingContent = content;
1537
+ this.opcode('invokeAmbiguous', name, isBlock);
1450
1538
  },
1451
1539
 
1452
- // [strip]
1453
- //
1454
- // On stack, before: ...
1455
- // On stack, after: ...
1456
- //
1457
- // Removes any trailing whitespace from the prior content node and flags
1458
- // the next operation for stripping if it is a content node.
1459
- strip: function() {
1460
- if (this.pendingContent) {
1461
- this.pendingContent = this.pendingContent.replace(/\s+$/, '');
1540
+ simpleSexpr: function(sexpr) {
1541
+ var id = sexpr.id;
1542
+
1543
+ if (id.type === 'DATA') {
1544
+ this.DATA(id);
1545
+ } else if (id.parts.length) {
1546
+ this.ID(id);
1547
+ } else {
1548
+ // Simplified ID for `this`
1549
+ this.addDepth(id.depth);
1550
+ this.opcode('getContext', id.depth);
1551
+ this.opcode('pushContext');
1462
1552
  }
1463
- this.stripNext = 'strip';
1553
+
1554
+ this.opcode('resolvePossibleLambda');
1464
1555
  },
1465
1556
 
1466
- // [append]
1467
- //
1468
- // On stack, before: value, ...
1469
- // On stack, after: ...
1470
- //
1471
- // Coerces `value` to a String and appends it to the current buffer.
1472
- //
1473
- // If `value` is truthy, or 0, it is coerced into a string and appended
1474
- // Otherwise, the empty string is appended
1475
- append: function() {
1476
- // Force anything that is inlined onto the stack so we don't have duplication
1477
- // when we examine local
1478
- this.flushInline();
1479
- var local = this.popStack();
1480
- this.pushSource("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1481
- if (this.environment.isSimple) {
1482
- this.pushSource("else { " + this.appendToBuffer("''") + " }");
1557
+ helperSexpr: function(sexpr, program, inverse) {
1558
+ var params = this.setupFullMustacheParams(sexpr, program, inverse),
1559
+ name = sexpr.id.parts[0];
1560
+
1561
+ if (this.options.knownHelpers[name]) {
1562
+ this.opcode('invokeKnownHelper', params.length, name);
1563
+ } else if (this.options.knownHelpersOnly) {
1564
+ throw new Exception("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
1565
+ } else {
1566
+ this.opcode('invokeHelper', params.length, name, sexpr.isRoot);
1483
1567
  }
1484
1568
  },
1485
1569
 
1486
- // [appendEscaped]
1487
- //
1488
- // On stack, before: value, ...
1489
- // On stack, after: ...
1490
- //
1491
- // Escape `value` and append it to the buffer
1492
- appendEscaped: function() {
1493
- this.context.aliases.escapeExpression = 'this.escapeExpression';
1570
+ sexpr: function(sexpr) {
1571
+ var type = this.classifySexpr(sexpr);
1494
1572
 
1495
- this.pushSource(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
1573
+ if (type === "simple") {
1574
+ this.simpleSexpr(sexpr);
1575
+ } else if (type === "helper") {
1576
+ this.helperSexpr(sexpr);
1577
+ } else {
1578
+ this.ambiguousSexpr(sexpr);
1579
+ }
1496
1580
  },
1497
1581
 
1498
- // [getContext]
1499
- //
1500
- // On stack, before: ...
1501
- // On stack, after: ...
1502
- // Compiler value, after: lastContext=depth
1503
- //
1504
- // Set the value of the `lastContext` compiler value to the depth
1505
- getContext: function(depth) {
1506
- if(this.lastContext !== depth) {
1507
- this.lastContext = depth;
1582
+ ID: function(id) {
1583
+ this.addDepth(id.depth);
1584
+ this.opcode('getContext', id.depth);
1585
+
1586
+ var name = id.parts[0];
1587
+ if (!name) {
1588
+ this.opcode('pushContext');
1589
+ } else {
1590
+ this.opcode('lookupOnContext', id.parts[0]);
1508
1591
  }
1509
- },
1510
1592
 
1511
- // [lookupOnContext]
1512
- //
1513
- // On stack, before: ...
1514
- // On stack, after: currentContext[name], ...
1515
- //
1516
- // Looks up the value of `name` on the current context and pushes
1517
- // it onto the stack.
1518
- lookupOnContext: function(name) {
1519
- this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
1593
+ for(var i=1, l=id.parts.length; i<l; i++) {
1594
+ this.opcode('lookup', id.parts[i]);
1595
+ }
1520
1596
  },
1521
1597
 
1522
- // [pushContext]
1523
- //
1524
- // On stack, before: ...
1525
- // On stack, after: currentContext, ...
1526
- //
1527
- // Pushes the value of the current context onto the stack.
1528
- pushContext: function() {
1529
- this.pushStackLiteral('depth' + this.lastContext);
1530
- },
1598
+ DATA: function(data) {
1599
+ this.options.data = true;
1600
+ if (data.id.isScoped || data.id.depth) {
1601
+ throw new Exception('Scoped data references are not supported: ' + data.original, data);
1602
+ }
1531
1603
 
1532
- // [resolvePossibleLambda]
1533
- //
1534
- // On stack, before: value, ...
1535
- // On stack, after: resolved value, ...
1536
- //
1537
- // If the `value` is a lambda, replace it on the stack by
1538
- // the return value of the lambda
1539
- resolvePossibleLambda: function() {
1540
- this.context.aliases.functionType = '"function"';
1604
+ this.opcode('lookupData');
1605
+ var parts = data.id.parts;
1606
+ for(var i=0, l=parts.length; i<l; i++) {
1607
+ this.opcode('lookup', parts[i]);
1608
+ }
1609
+ },
1541
1610
 
1542
- this.replaceStack(function(current) {
1543
- return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
1544
- });
1611
+ STRING: function(string) {
1612
+ this.opcode('pushString', string.string);
1545
1613
  },
1546
1614
 
1547
- // [lookup]
1548
- //
1549
- // On stack, before: value, ...
1550
- // On stack, after: value[name], ...
1551
- //
1552
- // Replace the value on the stack with the result of looking
1553
- // up `name` on `value`
1554
- lookup: function(name) {
1555
- this.replaceStack(function(current) {
1556
- return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
1557
- });
1615
+ INTEGER: function(integer) {
1616
+ this.opcode('pushLiteral', integer.integer);
1558
1617
  },
1559
1618
 
1560
- // [lookupData]
1561
- //
1562
- // On stack, before: ...
1563
- // On stack, after: data, ...
1564
- //
1565
- // Push the data lookup operator
1566
- lookupData: function() {
1567
- this.push('data');
1619
+ BOOLEAN: function(bool) {
1620
+ this.opcode('pushLiteral', bool.bool);
1568
1621
  },
1569
1622
 
1570
- // [pushStringParam]
1571
- //
1572
- // On stack, before: ...
1573
- // On stack, after: string, currentContext, ...
1574
- //
1575
- // This opcode is designed for use in string mode, which
1576
- // provides the string value of a parameter along with its
1577
- // depth rather than resolving it immediately.
1578
- pushStringParam: function(string, type) {
1579
- this.pushStackLiteral('depth' + this.lastContext);
1623
+ comment: function() {},
1580
1624
 
1581
- this.pushString(type);
1625
+ // HELPERS
1626
+ opcode: function(name) {
1627
+ this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
1628
+ },
1582
1629
 
1583
- if (typeof string === 'string') {
1584
- this.pushString(string);
1585
- } else {
1586
- this.pushStackLiteral(string);
1587
- }
1630
+ declare: function(name, value) {
1631
+ this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
1588
1632
  },
1589
1633
 
1590
- emptyHash: function() {
1591
- this.pushStackLiteral('{}');
1634
+ addDepth: function(depth) {
1635
+ if(depth === 0) { return; }
1592
1636
 
1593
- if (this.options.stringParams) {
1594
- this.register('hashTypes', '{}');
1595
- this.register('hashContexts', '{}');
1637
+ if(!this.depths[depth]) {
1638
+ this.depths[depth] = true;
1639
+ this.depths.list.push(depth);
1596
1640
  }
1597
1641
  },
1598
- pushHash: function() {
1599
- this.hash = {values: [], types: [], contexts: []};
1600
- },
1601
- popHash: function() {
1602
- var hash = this.hash;
1603
- this.hash = undefined;
1604
1642
 
1605
- if (this.options.stringParams) {
1606
- this.register('hashContexts', '{' + hash.contexts.join(',') + '}');
1607
- this.register('hashTypes', '{' + hash.types.join(',') + '}');
1643
+ classifySexpr: function(sexpr) {
1644
+ var isHelper = sexpr.isHelper;
1645
+ var isEligible = sexpr.eligibleHelper;
1646
+ var options = this.options;
1647
+
1648
+ // if ambiguous, we can possibly resolve the ambiguity now
1649
+ if (isEligible && !isHelper) {
1650
+ var name = sexpr.id.parts[0];
1651
+
1652
+ if (options.knownHelpers[name]) {
1653
+ isHelper = true;
1654
+ } else if (options.knownHelpersOnly) {
1655
+ isEligible = false;
1656
+ }
1608
1657
  }
1609
- this.push('{\n ' + hash.values.join(',\n ') + '\n }');
1610
- },
1611
1658
 
1612
- // [pushString]
1613
- //
1614
- // On stack, before: ...
1615
- // On stack, after: quotedString(string), ...
1616
- //
1617
- // Push a quoted version of `string` onto the stack
1618
- pushString: function(string) {
1619
- this.pushStackLiteral(this.quotedString(string));
1659
+ if (isHelper) { return "helper"; }
1660
+ else if (isEligible) { return "ambiguous"; }
1661
+ else { return "simple"; }
1620
1662
  },
1621
1663
 
1622
- // [push]
1623
- //
1624
- // On stack, before: ...
1625
- // On stack, after: expr, ...
1626
- //
1627
- // Push an expression onto the stack
1628
- push: function(expr) {
1629
- this.inlineStack.push(expr);
1630
- return expr;
1631
- },
1664
+ pushParams: function(params) {
1665
+ var i = params.length, param;
1632
1666
 
1633
- // [pushLiteral]
1634
- //
1635
- // On stack, before: ...
1636
- // On stack, after: value, ...
1637
- //
1638
- // Pushes a value onto the stack. This operation prevents
1639
- // the compiler from creating a temporary variable to hold
1640
- // it.
1641
- pushLiteral: function(value) {
1642
- this.pushStackLiteral(value);
1643
- },
1667
+ while(i--) {
1668
+ param = params[i];
1644
1669
 
1645
- // [pushProgram]
1646
- //
1647
- // On stack, before: ...
1648
- // On stack, after: program(guid), ...
1649
- //
1650
- // Push a program expression onto the stack. This takes
1651
- // a compile-time guid and converts it into a runtime-accessible
1652
- // expression.
1653
- pushProgram: function(guid) {
1654
- if (guid != null) {
1655
- this.pushStackLiteral(this.programExpression(guid));
1656
- } else {
1657
- this.pushStackLiteral(null);
1670
+ if(this.options.stringParams) {
1671
+ if(param.depth) {
1672
+ this.addDepth(param.depth);
1673
+ }
1674
+
1675
+ this.opcode('getContext', param.depth || 0);
1676
+ this.opcode('pushStringParam', param.stringModeValue, param.type);
1677
+
1678
+ if (param.type === 'sexpr') {
1679
+ // Subexpressions get evaluated and passed in
1680
+ // in string params mode.
1681
+ this.sexpr(param);
1682
+ }
1683
+ } else {
1684
+ this[param.type](param);
1685
+ }
1658
1686
  }
1659
1687
  },
1660
1688
 
1661
- // [invokeHelper]
1662
- //
1663
- // On stack, before: hash, inverse, program, params..., ...
1664
- // On stack, after: result of helper invocation
1665
- //
1666
- // Pops off the helper's parameters, invokes the helper,
1667
- // and pushes the helper's return value onto the stack.
1668
- //
1669
- // If the helper is not found, `helperMissing` is called.
1670
- invokeHelper: function(paramSize, name) {
1671
- this.context.aliases.helperMissing = 'helpers.helperMissing';
1689
+ setupFullMustacheParams: function(sexpr, program, inverse) {
1690
+ var params = sexpr.params;
1691
+ this.pushParams(params);
1672
1692
 
1673
- var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
1674
- var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1693
+ this.opcode('pushProgram', program);
1694
+ this.opcode('pushProgram', inverse);
1675
1695
 
1676
- this.push(helper.name + ' || ' + nonHelper);
1677
- this.replaceStack(function(name) {
1678
- return name + ' ? ' + name + '.call(' +
1679
- helper.callParams + ") " + ": helperMissing.call(" +
1680
- helper.helperMissingParams + ")";
1681
- });
1682
- },
1696
+ if (sexpr.hash) {
1697
+ this.hash(sexpr.hash);
1698
+ } else {
1699
+ this.opcode('emptyHash');
1700
+ }
1683
1701
 
1684
- // [invokeKnownHelper]
1685
- //
1686
- // On stack, before: hash, inverse, program, params..., ...
1687
- // On stack, after: result of helper invocation
1688
- //
1689
- // This operation is used when the helper is known to exist,
1690
- // so a `helperMissing` fallback is not required.
1691
- invokeKnownHelper: function(paramSize, name) {
1692
- var helper = this.setupHelper(paramSize, name);
1693
- this.push(helper.name + ".call(" + helper.callParams + ")");
1694
- },
1702
+ return params;
1703
+ }
1704
+ };
1695
1705
 
1696
- // [invokeAmbiguous]
1697
- //
1698
- // On stack, before: hash, inverse, program, params..., ...
1699
- // On stack, after: result of disambiguation
1700
- //
1701
- // This operation is used when an expression like `{{foo}}`
1702
- // is provided, but we don't know at compile-time whether it
1703
- // is a helper or a path.
1704
- //
1705
- // This operation emits more code than the other options,
1706
- // and can be avoided by passing the `knownHelpers` and
1707
- // `knownHelpersOnly` flags at compile-time.
1708
- invokeAmbiguous: function(name, helperCall) {
1709
- this.context.aliases.functionType = '"function"';
1706
+ function precompile(input, options, env) {
1707
+ if (input == null || (typeof input !== 'string' && input.constructor !== env.AST.ProgramNode)) {
1708
+ throw new Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
1709
+ }
1710
1710
 
1711
- this.pushStackLiteral('{}'); // Hash value
1712
- var helper = this.setupHelper(0, name, helperCall);
1711
+ options = options || {};
1712
+ if (!('data' in options)) {
1713
+ options.data = true;
1714
+ }
1713
1715
 
1714
- var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
1716
+ var ast = env.parse(input);
1717
+ var environment = new env.Compiler().compile(ast, options);
1718
+ return new env.JavaScriptCompiler().compile(environment, options);
1719
+ }
1715
1720
 
1716
- var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1717
- var nextStack = this.nextStack();
1721
+ __exports__.precompile = precompile;function compile(input, options, env) {
1722
+ if (input == null || (typeof input !== 'string' && input.constructor !== env.AST.ProgramNode)) {
1723
+ throw new Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
1724
+ }
1718
1725
 
1719
- this.pushSource('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
1720
- this.pushSource('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.call(' + helper.callParams + ') : ' + nextStack + '; }');
1721
- },
1726
+ options = options || {};
1722
1727
 
1723
- // [invokePartial]
1724
- //
1725
- // On stack, before: context, ...
1726
- // On stack after: result of partial invocation
1727
- //
1728
- // This operation pops off a context, invokes a partial with that context,
1729
- // and pushes the result of the invocation back.
1730
- invokePartial: function(name) {
1731
- var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
1728
+ if (!('data' in options)) {
1729
+ options.data = true;
1730
+ }
1732
1731
 
1733
- if (this.options.data) {
1734
- params.push("data");
1732
+ var compiled;
1733
+
1734
+ function compileInput() {
1735
+ var ast = env.parse(input);
1736
+ var environment = new env.Compiler().compile(ast, options);
1737
+ var templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
1738
+ return env.template(templateSpec);
1739
+ }
1740
+
1741
+ // Template is only compiled on first use and cached after that point.
1742
+ return function(context, options) {
1743
+ if (!compiled) {
1744
+ compiled = compileInput();
1735
1745
  }
1746
+ return compiled.call(this, context, options);
1747
+ };
1748
+ }
1736
1749
 
1737
- this.context.aliases.self = "this";
1738
- this.push("self.invokePartial(" + params.join(", ") + ")");
1739
- },
1750
+ __exports__.compile = compile;
1751
+ return __exports__;
1752
+ })(__module5__);
1740
1753
 
1741
- // [assignToHash]
1742
- //
1743
- // On stack, before: value, hash, ...
1744
- // On stack, after: hash, ...
1745
- //
1746
- // Pops a value and hash off the stack, assigns `hash[key] = value`
1747
- // and pushes the hash back onto the stack.
1748
- assignToHash: function(key) {
1749
- var value = this.popStack(),
1750
- context,
1751
- type;
1754
+ // handlebars/compiler/javascript-compiler.js
1755
+ var __module11__ = (function(__dependency1__, __dependency2__) {
1756
+ "use strict";
1757
+ var __exports__;
1758
+ var COMPILER_REVISION = __dependency1__.COMPILER_REVISION;
1759
+ var REVISION_CHANGES = __dependency1__.REVISION_CHANGES;
1760
+ var log = __dependency1__.log;
1761
+ var Exception = __dependency2__;
1752
1762
 
1753
- if (this.options.stringParams) {
1754
- type = this.popStack();
1755
- context = this.popStack();
1763
+ function Literal(value) {
1764
+ this.value = value;
1765
+ }
1766
+
1767
+ function JavaScriptCompiler() {}
1768
+
1769
+ JavaScriptCompiler.prototype = {
1770
+ // PUBLIC API: You can override these methods in a subclass to provide
1771
+ // alternative compiled forms for name lookup and buffering semantics
1772
+ nameLookup: function(parent, name /* , type*/) {
1773
+ var wrap,
1774
+ ret;
1775
+ if (parent.indexOf('depth') === 0) {
1776
+ wrap = true;
1756
1777
  }
1757
1778
 
1758
- var hash = this.hash;
1759
- if (context) {
1760
- hash.contexts.push("'" + key + "': " + context);
1779
+ if (/^[0-9]+$/.test(name)) {
1780
+ ret = parent + "[" + name + "]";
1781
+ } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1782
+ ret = parent + "." + name;
1761
1783
  }
1762
- if (type) {
1763
- hash.types.push("'" + key + "': " + type);
1784
+ else {
1785
+ ret = parent + "['" + name + "']";
1786
+ }
1787
+
1788
+ if (wrap) {
1789
+ return '(' + parent + ' && ' + ret + ')';
1790
+ } else {
1791
+ return ret;
1764
1792
  }
1765
- hash.values.push("'" + key + "': (" + value + ")");
1766
1793
  },
1767
1794
 
1768
- // HELPERS
1795
+ compilerInfo: function() {
1796
+ var revision = COMPILER_REVISION,
1797
+ versions = REVISION_CHANGES[revision];
1798
+ return "this.compilerInfo = ["+revision+",'"+versions+"'];\n";
1799
+ },
1769
1800
 
1770
- compiler: JavaScriptCompiler,
1801
+ appendToBuffer: function(string) {
1802
+ if (this.environment.isSimple) {
1803
+ return "return " + string + ";";
1804
+ } else {
1805
+ return {
1806
+ appendToBuffer: true,
1807
+ content: string,
1808
+ toString: function() { return "buffer += " + string + ";"; }
1809
+ };
1810
+ }
1811
+ },
1771
1812
 
1772
- compileChildren: function(environment, options) {
1773
- var children = environment.children, child, compiler;
1813
+ initializeBuffer: function() {
1814
+ return this.quotedString("");
1815
+ },
1774
1816
 
1775
- for(var i=0, l=children.length; i<l; i++) {
1776
- child = children[i];
1777
- compiler = new this.compiler();
1817
+ namespace: "Handlebars",
1818
+ // END PUBLIC API
1778
1819
 
1779
- var index = this.matchExistingProgram(child);
1820
+ compile: function(environment, options, context, asObject) {
1821
+ this.environment = environment;
1822
+ this.options = options || {};
1780
1823
 
1781
- if (index == null) {
1782
- this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
1783
- index = this.context.programs.length;
1784
- child.index = index;
1785
- child.name = 'program' + index;
1786
- this.context.programs[index] = compiler.compile(child, options, this.context);
1787
- this.context.environments[index] = child;
1824
+ log('debug', this.environment.disassemble() + "\n\n");
1825
+
1826
+ this.name = this.environment.name;
1827
+ this.isChild = !!context;
1828
+ this.context = context || {
1829
+ programs: [],
1830
+ environments: [],
1831
+ aliases: { }
1832
+ };
1833
+
1834
+ this.preamble();
1835
+
1836
+ this.stackSlot = 0;
1837
+ this.stackVars = [];
1838
+ this.registers = { list: [] };
1839
+ this.hashes = [];
1840
+ this.compileStack = [];
1841
+ this.inlineStack = [];
1842
+
1843
+ this.compileChildren(environment, options);
1844
+
1845
+ var opcodes = environment.opcodes, opcode;
1846
+
1847
+ this.i = 0;
1848
+
1849
+ for(var l=opcodes.length; this.i<l; this.i++) {
1850
+ opcode = opcodes[this.i];
1851
+
1852
+ if(opcode.opcode === 'DECLARE') {
1853
+ this[opcode.name] = opcode.value;
1788
1854
  } else {
1789
- child.index = index;
1790
- child.name = 'program' + index;
1855
+ this[opcode.opcode].apply(this, opcode.args);
1791
1856
  }
1792
- }
1793
- },
1794
- matchExistingProgram: function(child) {
1795
- for (var i = 0, len = this.context.environments.length; i < len; i++) {
1796
- var environment = this.context.environments[i];
1797
- if (environment && environment.equals(child)) {
1798
- return i;
1857
+
1858
+ // Reset the stripNext flag if it was not set by this operation.
1859
+ if (opcode.opcode !== this.stripNext) {
1860
+ this.stripNext = false;
1799
1861
  }
1800
1862
  }
1801
- },
1802
1863
 
1803
- programExpression: function(guid) {
1804
- this.context.aliases.self = "this";
1864
+ // Flush any trailing content that might be pending.
1865
+ this.pushSource('');
1805
1866
 
1806
- if(guid == null) {
1807
- return "self.noop";
1867
+ if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {
1868
+ throw new Exception('Compile completed with content left on stack');
1808
1869
  }
1809
1870
 
1810
- var child = this.environment.children[guid],
1811
- depths = child.depths.list, depth;
1871
+ return this.createFunctionContext(asObject);
1872
+ },
1812
1873
 
1813
- var programParams = [child.index, child.name, "data"];
1874
+ preamble: function() {
1875
+ var out = [];
1814
1876
 
1815
- for(var i=0, l = depths.length; i<l; i++) {
1816
- depth = depths[i];
1877
+ if (!this.isChild) {
1878
+ var namespace = this.namespace;
1817
1879
 
1818
- if(depth === 1) { programParams.push("depth0"); }
1819
- else { programParams.push("depth" + (depth - 1)); }
1880
+ var copies = "helpers = this.merge(helpers, " + namespace + ".helpers);";
1881
+ if (this.environment.usePartial) { copies = copies + " partials = this.merge(partials, " + namespace + ".partials);"; }
1882
+ if (this.options.data) { copies = copies + " data = data || {};"; }
1883
+ out.push(copies);
1884
+ } else {
1885
+ out.push('');
1820
1886
  }
1821
1887
 
1822
- return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")";
1823
- },
1888
+ if (!this.environment.isSimple) {
1889
+ out.push(", buffer = " + this.initializeBuffer());
1890
+ } else {
1891
+ out.push("");
1892
+ }
1824
1893
 
1825
- register: function(name, val) {
1826
- this.useRegister(name);
1827
- this.pushSource(name + " = " + val + ";");
1894
+ // track the last context pushed into place to allow skipping the
1895
+ // getContext opcode when it would be a noop
1896
+ this.lastContext = 0;
1897
+ this.source = out;
1828
1898
  },
1829
1899
 
1830
- useRegister: function(name) {
1831
- if(!this.registers[name]) {
1832
- this.registers[name] = true;
1833
- this.registers.list.push(name);
1900
+ createFunctionContext: function(asObject) {
1901
+ var locals = this.stackVars.concat(this.registers.list);
1902
+
1903
+ if(locals.length > 0) {
1904
+ this.source[1] = this.source[1] + ", " + locals.join(", ");
1834
1905
  }
1835
- },
1836
1906
 
1837
- pushStackLiteral: function(item) {
1838
- return this.push(new Literal(item));
1839
- },
1907
+ // Generate minimizer alias mappings
1908
+ if (!this.isChild) {
1909
+ for (var alias in this.context.aliases) {
1910
+ if (this.context.aliases.hasOwnProperty(alias)) {
1911
+ this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1912
+ }
1913
+ }
1914
+ }
1840
1915
 
1841
- pushSource: function(source) {
1842
- if (this.pendingContent) {
1843
- this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent)));
1844
- this.pendingContent = undefined;
1916
+ if (this.source[1]) {
1917
+ this.source[1] = "var " + this.source[1].substring(2) + ";";
1845
1918
  }
1846
1919
 
1847
- if (source) {
1848
- this.source.push(source);
1920
+ // Merge children
1921
+ if (!this.isChild) {
1922
+ this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1849
1923
  }
1850
- },
1851
1924
 
1852
- pushStack: function(item) {
1853
- this.flushInline();
1925
+ if (!this.environment.isSimple) {
1926
+ this.pushSource("return buffer;");
1927
+ }
1854
1928
 
1855
- var stack = this.incrStack();
1856
- if (item) {
1857
- this.pushSource(stack + " = " + item + ";");
1929
+ var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1930
+
1931
+ for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1932
+ params.push("depth" + this.environment.depths.list[i]);
1858
1933
  }
1859
- this.compileStack.push(stack);
1860
- return stack;
1861
- },
1862
1934
 
1863
- replaceStack: function(callback) {
1864
- var prefix = '',
1865
- inline = this.isInline(),
1866
- stack;
1935
+ // Perform a second pass over the output to merge content when possible
1936
+ var source = this.mergeSource();
1867
1937
 
1868
- // If we are currently inline then we want to merge the inline statement into the
1869
- // replacement statement via ','
1870
- if (inline) {
1871
- var top = this.popStack(true);
1872
-
1873
- if (top instanceof Literal) {
1874
- // Literals do not need to be inlined
1875
- stack = top.value;
1876
- } else {
1877
- // Get or create the current stack name for use by the inline
1878
- var name = this.stackSlot ? this.topStackName() : this.incrStack();
1879
-
1880
- prefix = '(' + this.push(name) + ' = ' + top + '),';
1881
- stack = this.topStack();
1882
- }
1883
- } else {
1884
- stack = this.topStack();
1938
+ if (!this.isChild) {
1939
+ source = this.compilerInfo()+source;
1885
1940
  }
1886
1941
 
1887
- var item = callback.call(this, stack);
1942
+ if (asObject) {
1943
+ params.push(source);
1888
1944
 
1889
- if (inline) {
1890
- if (this.inlineStack.length || this.compileStack.length) {
1891
- this.popStack();
1892
- }
1893
- this.push('(' + prefix + item + ')');
1945
+ return Function.apply(this, params);
1894
1946
  } else {
1895
- // Prevent modification of the context depth variable. Through replaceStack
1896
- if (!/^stack/.test(stack)) {
1897
- stack = this.nextStack();
1898
- }
1899
-
1900
- this.pushSource(stack + " = (" + prefix + item + ");");
1947
+ var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
1948
+ log('debug', functionSource + "\n\n");
1949
+ return functionSource;
1901
1950
  }
1902
- return stack;
1903
- },
1904
-
1905
- nextStack: function() {
1906
- return this.pushStack();
1907
1951
  },
1908
-
1909
- incrStack: function() {
1910
- this.stackSlot++;
1911
- if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1912
- return this.topStackName();
1913
- },
1914
- topStackName: function() {
1915
- return "stack" + this.stackSlot;
1916
- },
1917
- flushInline: function() {
1918
- var inlineStack = this.inlineStack;
1919
- if (inlineStack.length) {
1920
- this.inlineStack = [];
1921
- for (var i = 0, len = inlineStack.length; i < len; i++) {
1922
- var entry = inlineStack[i];
1923
- if (entry instanceof Literal) {
1924
- this.compileStack.push(entry);
1952
+ mergeSource: function() {
1953
+ // WARN: We are not handling the case where buffer is still populated as the source should
1954
+ // not have buffer append operations as their final action.
1955
+ var source = '',
1956
+ buffer;
1957
+ for (var i = 0, len = this.source.length; i < len; i++) {
1958
+ var line = this.source[i];
1959
+ if (line.appendToBuffer) {
1960
+ if (buffer) {
1961
+ buffer = buffer + '\n + ' + line.content;
1925
1962
  } else {
1926
- this.pushStack(entry);
1963
+ buffer = line.content;
1927
1964
  }
1965
+ } else {
1966
+ if (buffer) {
1967
+ source += 'buffer += ' + buffer + ';\n ';
1968
+ buffer = undefined;
1969
+ }
1970
+ source += line + '\n ';
1928
1971
  }
1929
1972
  }
1930
- },
1931
- isInline: function() {
1932
- return this.inlineStack.length;
1933
- },
1934
-
1935
- popStack: function(wrapped) {
1936
- var inline = this.isInline(),
1937
- item = (inline ? this.inlineStack : this.compileStack).pop();
1938
-
1939
- if (!wrapped && (item instanceof Literal)) {
1940
- return item.value;
1941
- } else {
1942
- if (!inline) {
1943
- this.stackSlot--;
1944
- }
1945
- return item;
1946
- }
1947
- },
1948
-
1949
- topStack: function(wrapped) {
1950
- var stack = (this.isInline() ? this.inlineStack : this.compileStack),
1951
- item = stack[stack.length - 1];
1952
-
1953
- if (!wrapped && (item instanceof Literal)) {
1954
- return item.value;
1955
- } else {
1956
- return item;
1957
- }
1973
+ return source;
1958
1974
  },
1959
1975
 
1960
- quotedString: function(str) {
1961
- return '"' + str
1962
- .replace(/\\/g, '\\\\')
1963
- .replace(/"/g, '\\"')
1964
- .replace(/\n/g, '\\n')
1965
- .replace(/\r/g, '\\r')
1966
- .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
1967
- .replace(/\u2029/g, '\\u2029') + '"';
1968
- },
1976
+ // [blockValue]
1977
+ //
1978
+ // On stack, before: hash, inverse, program, value
1979
+ // On stack, after: return value of blockHelperMissing
1980
+ //
1981
+ // The purpose of this opcode is to take a block of the form
1982
+ // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
1983
+ // replace it on the stack with the result of properly
1984
+ // invoking blockHelperMissing.
1985
+ blockValue: function() {
1986
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1969
1987
 
1970
- setupHelper: function(paramSize, name, missingParams) {
1971
- var params = [];
1972
- this.setupParams(paramSize, params, missingParams);
1973
- var foundHelper = this.nameLookup('helpers', name, 'helper');
1988
+ var params = ["depth0"];
1989
+ this.setupParams(0, params);
1974
1990
 
1975
- return {
1976
- params: params,
1977
- name: foundHelper,
1978
- callParams: ["depth0"].concat(params).join(", "),
1979
- helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
1980
- };
1991
+ this.replaceStack(function(current) {
1992
+ params.splice(1, 0, current);
1993
+ return "blockHelperMissing.call(" + params.join(", ") + ")";
1994
+ });
1981
1995
  },
1982
1996
 
1983
- // the params and contexts arguments are passed in arrays
1984
- // to fill in
1985
- setupParams: function(paramSize, params, useRegister) {
1986
- var options = [], contexts = [], types = [], param, inverse, program;
1987
-
1988
- options.push("hash:" + this.popStack());
1997
+ // [ambiguousBlockValue]
1998
+ //
1999
+ // On stack, before: hash, inverse, program, value
2000
+ // Compiler value, before: lastHelper=value of last found helper, if any
2001
+ // On stack, after, if no lastHelper: same as [blockValue]
2002
+ // On stack, after, if lastHelper: value
2003
+ ambiguousBlockValue: function() {
2004
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1989
2005
 
1990
- inverse = this.popStack();
1991
- program = this.popStack();
2006
+ var params = ["depth0"];
2007
+ this.setupParams(0, params);
1992
2008
 
1993
- // Avoid setting fn and inverse if neither are set. This allows
1994
- // helpers to do a check for `if (options.fn)`
1995
- if (program || inverse) {
1996
- if (!program) {
1997
- this.context.aliases.self = "this";
1998
- program = "self.noop";
1999
- }
2009
+ var current = this.topStack();
2010
+ params.splice(1, 0, current);
2000
2011
 
2001
- if (!inverse) {
2002
- this.context.aliases.self = "this";
2003
- inverse = "self.noop";
2004
- }
2012
+ this.pushSource("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
2013
+ },
2005
2014
 
2006
- options.push("inverse:" + inverse);
2007
- options.push("fn:" + program);
2015
+ // [appendContent]
2016
+ //
2017
+ // On stack, before: ...
2018
+ // On stack, after: ...
2019
+ //
2020
+ // Appends the string value of `content` to the current buffer
2021
+ appendContent: function(content) {
2022
+ if (this.pendingContent) {
2023
+ content = this.pendingContent + content;
2008
2024
  }
2009
-
2010
- for(var i=0; i<paramSize; i++) {
2011
- param = this.popStack();
2012
- params.push(param);
2013
-
2014
- if(this.options.stringParams) {
2015
- types.push(this.popStack());
2016
- contexts.push(this.popStack());
2017
- }
2025
+ if (this.stripNext) {
2026
+ content = content.replace(/^\s+/, '');
2018
2027
  }
2019
2028
 
2020
- if (this.options.stringParams) {
2021
- options.push("contexts:[" + contexts.join(",") + "]");
2022
- options.push("types:[" + types.join(",") + "]");
2023
- options.push("hashContexts:hashContexts");
2024
- options.push("hashTypes:hashTypes");
2025
- }
2029
+ this.pendingContent = content;
2030
+ },
2026
2031
 
2027
- if(this.options.data) {
2028
- options.push("data:data");
2032
+ // [strip]
2033
+ //
2034
+ // On stack, before: ...
2035
+ // On stack, after: ...
2036
+ //
2037
+ // Removes any trailing whitespace from the prior content node and flags
2038
+ // the next operation for stripping if it is a content node.
2039
+ strip: function() {
2040
+ if (this.pendingContent) {
2041
+ this.pendingContent = this.pendingContent.replace(/\s+$/, '');
2029
2042
  }
2043
+ this.stripNext = 'strip';
2044
+ },
2030
2045
 
2031
- options = "{" + options.join(",") + "}";
2032
- if (useRegister) {
2033
- this.register('options', options);
2034
- params.push('options');
2035
- } else {
2036
- params.push(options);
2046
+ // [append]
2047
+ //
2048
+ // On stack, before: value, ...
2049
+ // On stack, after: ...
2050
+ //
2051
+ // Coerces `value` to a String and appends it to the current buffer.
2052
+ //
2053
+ // If `value` is truthy, or 0, it is coerced into a string and appended
2054
+ // Otherwise, the empty string is appended
2055
+ append: function() {
2056
+ // Force anything that is inlined onto the stack so we don't have duplication
2057
+ // when we examine local
2058
+ this.flushInline();
2059
+ var local = this.popStack();
2060
+ this.pushSource("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
2061
+ if (this.environment.isSimple) {
2062
+ this.pushSource("else { " + this.appendToBuffer("''") + " }");
2037
2063
  }
2038
- return params.join(", ");
2039
- }
2040
- };
2064
+ },
2041
2065
 
2042
- var reservedWords = (
2043
- "break else new var" +
2044
- " case finally return void" +
2045
- " catch for switch while" +
2046
- " continue function this with" +
2047
- " default if throw" +
2048
- " delete in try" +
2049
- " do instanceof typeof" +
2050
- " abstract enum int short" +
2051
- " boolean export interface static" +
2052
- " byte extends long super" +
2053
- " char final native synchronized" +
2054
- " class float package throws" +
2055
- " const goto private transient" +
2056
- " debugger implements protected volatile" +
2057
- " double import public let yield"
2058
- ).split(" ");
2066
+ // [appendEscaped]
2067
+ //
2068
+ // On stack, before: value, ...
2069
+ // On stack, after: ...
2070
+ //
2071
+ // Escape `value` and append it to the buffer
2072
+ appendEscaped: function() {
2073
+ this.context.aliases.escapeExpression = 'this.escapeExpression';
2059
2074
 
2060
- var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
2075
+ this.pushSource(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
2076
+ },
2061
2077
 
2062
- for(var i=0, l=reservedWords.length; i<l; i++) {
2063
- compilerWords[reservedWords[i]] = true;
2064
- }
2078
+ // [getContext]
2079
+ //
2080
+ // On stack, before: ...
2081
+ // On stack, after: ...
2082
+ // Compiler value, after: lastContext=depth
2083
+ //
2084
+ // Set the value of the `lastContext` compiler value to the depth
2085
+ getContext: function(depth) {
2086
+ if(this.lastContext !== depth) {
2087
+ this.lastContext = depth;
2088
+ }
2089
+ },
2065
2090
 
2066
- JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
2067
- if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
2068
- return true;
2069
- }
2070
- return false;
2071
- };
2091
+ // [lookupOnContext]
2092
+ //
2093
+ // On stack, before: ...
2094
+ // On stack, after: currentContext[name], ...
2095
+ //
2096
+ // Looks up the value of `name` on the current context and pushes
2097
+ // it onto the stack.
2098
+ lookupOnContext: function(name) {
2099
+ this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
2100
+ },
2072
2101
 
2073
- __exports__ = JavaScriptCompiler;
2074
- return __exports__;
2075
- })(__module2__);
2102
+ // [pushContext]
2103
+ //
2104
+ // On stack, before: ...
2105
+ // On stack, after: currentContext, ...
2106
+ //
2107
+ // Pushes the value of the current context onto the stack.
2108
+ pushContext: function() {
2109
+ this.pushStackLiteral('depth' + this.lastContext);
2110
+ },
2076
2111
 
2077
- // handlebars/compiler/compiler.js
2078
- var __module10__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) {
2079
- "use strict";
2080
- var __exports__ = {};
2081
- var Exception = __dependency1__;
2082
- var parse = __dependency2__.parse;
2083
- var JavaScriptCompiler = __dependency3__;
2084
- var AST = __dependency4__;
2112
+ // [resolvePossibleLambda]
2113
+ //
2114
+ // On stack, before: value, ...
2115
+ // On stack, after: resolved value, ...
2116
+ //
2117
+ // If the `value` is a lambda, replace it on the stack by
2118
+ // the return value of the lambda
2119
+ resolvePossibleLambda: function() {
2120
+ this.context.aliases.functionType = '"function"';
2085
2121
 
2086
- function Compiler() {}
2122
+ this.replaceStack(function(current) {
2123
+ return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
2124
+ });
2125
+ },
2087
2126
 
2088
- __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a
2089
- // function in a context. This is necessary for mustache compatibility, which
2090
- // requires that context functions in blocks are evaluated by blockHelperMissing,
2091
- // and then proceed as if the resulting value was provided to blockHelperMissing.
2127
+ // [lookup]
2128
+ //
2129
+ // On stack, before: value, ...
2130
+ // On stack, after: value[name], ...
2131
+ //
2132
+ // Replace the value on the stack with the result of looking
2133
+ // up `name` on `value`
2134
+ lookup: function(name) {
2135
+ this.replaceStack(function(current) {
2136
+ return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
2137
+ });
2138
+ },
2092
2139
 
2093
- Compiler.prototype = {
2094
- compiler: Compiler,
2140
+ // [lookupData]
2141
+ //
2142
+ // On stack, before: ...
2143
+ // On stack, after: data, ...
2144
+ //
2145
+ // Push the data lookup operator
2146
+ lookupData: function() {
2147
+ this.pushStackLiteral('data');
2148
+ },
2095
2149
 
2096
- disassemble: function() {
2097
- var opcodes = this.opcodes, opcode, out = [], params, param;
2150
+ // [pushStringParam]
2151
+ //
2152
+ // On stack, before: ...
2153
+ // On stack, after: string, currentContext, ...
2154
+ //
2155
+ // This opcode is designed for use in string mode, which
2156
+ // provides the string value of a parameter along with its
2157
+ // depth rather than resolving it immediately.
2158
+ pushStringParam: function(string, type) {
2159
+ this.pushStackLiteral('depth' + this.lastContext);
2098
2160
 
2099
- for (var i=0, l=opcodes.length; i<l; i++) {
2100
- opcode = opcodes[i];
2161
+ this.pushString(type);
2101
2162
 
2102
- if (opcode.opcode === 'DECLARE') {
2103
- out.push("DECLARE " + opcode.name + "=" + opcode.value);
2163
+ // If it's a subexpression, the string result
2164
+ // will be pushed after this opcode.
2165
+ if (type !== 'sexpr') {
2166
+ if (typeof string === 'string') {
2167
+ this.pushString(string);
2104
2168
  } else {
2105
- params = [];
2106
- for (var j=0; j<opcode.args.length; j++) {
2107
- param = opcode.args[j];
2108
- if (typeof param === "string") {
2109
- param = "\"" + param.replace("\n", "\\n") + "\"";
2110
- }
2111
- params.push(param);
2112
- }
2113
- out.push(opcode.opcode + " " + params.join(" "));
2169
+ this.pushStackLiteral(string);
2114
2170
  }
2115
2171
  }
2116
-
2117
- return out.join("\n");
2118
2172
  },
2119
2173
 
2120
- equals: function(other) {
2121
- var len = this.opcodes.length;
2122
- if (other.opcodes.length !== len) {
2123
- return false;
2124
- }
2174
+ emptyHash: function() {
2175
+ this.pushStackLiteral('{}');
2125
2176
 
2126
- for (var i = 0; i < len; i++) {
2127
- var opcode = this.opcodes[i],
2128
- otherOpcode = other.opcodes[i];
2129
- if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
2130
- return false;
2131
- }
2132
- for (var j = 0; j < opcode.args.length; j++) {
2133
- if (opcode.args[j] !== otherOpcode.args[j]) {
2134
- return false;
2135
- }
2136
- }
2177
+ if (this.options.stringParams) {
2178
+ this.push('{}'); // hashContexts
2179
+ this.push('{}'); // hashTypes
2137
2180
  }
2138
-
2139
- len = this.children.length;
2140
- if (other.children.length !== len) {
2141
- return false;
2181
+ },
2182
+ pushHash: function() {
2183
+ if (this.hash) {
2184
+ this.hashes.push(this.hash);
2142
2185
  }
2143
- for (i = 0; i < len; i++) {
2144
- if (!this.children[i].equals(other.children[i])) {
2145
- return false;
2146
- }
2186
+ this.hash = {values: [], types: [], contexts: []};
2187
+ },
2188
+ popHash: function() {
2189
+ var hash = this.hash;
2190
+ this.hash = this.hashes.pop();
2191
+
2192
+ if (this.options.stringParams) {
2193
+ this.push('{' + hash.contexts.join(',') + '}');
2194
+ this.push('{' + hash.types.join(',') + '}');
2147
2195
  }
2148
2196
 
2149
- return true;
2197
+ this.push('{\n ' + hash.values.join(',\n ') + '\n }');
2150
2198
  },
2151
2199
 
2152
- guid: 0,
2153
-
2154
- compile: function(program, options) {
2155
- this.opcodes = [];
2156
- this.children = [];
2157
- this.depths = {list: []};
2158
- this.options = options;
2200
+ // [pushString]
2201
+ //
2202
+ // On stack, before: ...
2203
+ // On stack, after: quotedString(string), ...
2204
+ //
2205
+ // Push a quoted version of `string` onto the stack
2206
+ pushString: function(string) {
2207
+ this.pushStackLiteral(this.quotedString(string));
2208
+ },
2159
2209
 
2160
- // These changes will propagate to the other compiler components
2161
- var knownHelpers = this.options.knownHelpers;
2162
- this.options.knownHelpers = {
2163
- 'helperMissing': true,
2164
- 'blockHelperMissing': true,
2165
- 'each': true,
2166
- 'if': true,
2167
- 'unless': true,
2168
- 'with': true,
2169
- 'log': true
2170
- };
2171
- if (knownHelpers) {
2172
- for (var name in knownHelpers) {
2173
- this.options.knownHelpers[name] = knownHelpers[name];
2174
- }
2175
- }
2210
+ // [push]
2211
+ //
2212
+ // On stack, before: ...
2213
+ // On stack, after: expr, ...
2214
+ //
2215
+ // Push an expression onto the stack
2216
+ push: function(expr) {
2217
+ this.inlineStack.push(expr);
2218
+ return expr;
2219
+ },
2176
2220
 
2177
- return this.accept(program);
2221
+ // [pushLiteral]
2222
+ //
2223
+ // On stack, before: ...
2224
+ // On stack, after: value, ...
2225
+ //
2226
+ // Pushes a value onto the stack. This operation prevents
2227
+ // the compiler from creating a temporary variable to hold
2228
+ // it.
2229
+ pushLiteral: function(value) {
2230
+ this.pushStackLiteral(value);
2178
2231
  },
2179
2232
 
2180
- accept: function(node) {
2181
- var strip = node.strip || {},
2182
- ret;
2183
- if (strip.left) {
2184
- this.opcode('strip');
2233
+ // [pushProgram]
2234
+ //
2235
+ // On stack, before: ...
2236
+ // On stack, after: program(guid), ...
2237
+ //
2238
+ // Push a program expression onto the stack. This takes
2239
+ // a compile-time guid and converts it into a runtime-accessible
2240
+ // expression.
2241
+ pushProgram: function(guid) {
2242
+ if (guid != null) {
2243
+ this.pushStackLiteral(this.programExpression(guid));
2244
+ } else {
2245
+ this.pushStackLiteral(null);
2185
2246
  }
2247
+ },
2248
+
2249
+ // [invokeHelper]
2250
+ //
2251
+ // On stack, before: hash, inverse, program, params..., ...
2252
+ // On stack, after: result of helper invocation
2253
+ //
2254
+ // Pops off the helper's parameters, invokes the helper,
2255
+ // and pushes the helper's return value onto the stack.
2256
+ //
2257
+ // If the helper is not found, `helperMissing` is called.
2258
+ invokeHelper: function(paramSize, name, isRoot) {
2259
+ this.context.aliases.helperMissing = 'helpers.helperMissing';
2260
+ this.useRegister('helper');
2186
2261
 
2187
- ret = this[node.type](node);
2262
+ var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
2263
+ var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
2188
2264
 
2189
- if (strip.right) {
2190
- this.opcode('strip');
2265
+ var lookup = 'helper = ' + helper.name + ' || ' + nonHelper;
2266
+ if (helper.paramsInit) {
2267
+ lookup += ',' + helper.paramsInit;
2191
2268
  }
2192
2269
 
2193
- return ret;
2194
- },
2195
-
2196
- program: function(program) {
2197
- var statements = program.statements;
2270
+ this.push(
2271
+ '('
2272
+ + lookup
2273
+ + ',helper '
2274
+ + '? helper.call(' + helper.callParams + ') '
2275
+ + ': helperMissing.call(' + helper.helperMissingParams + '))');
2198
2276
 
2199
- for(var i=0, l=statements.length; i<l; i++) {
2200
- this.accept(statements[i]);
2277
+ // Always flush subexpressions. This is both to prevent the compounding size issue that
2278
+ // occurs when the code has to be duplicated for inlining and also to prevent errors
2279
+ // due to the incorrect options object being passed due to the shared register.
2280
+ if (!isRoot) {
2281
+ this.flushInline();
2201
2282
  }
2202
- this.isSimple = l === 1;
2203
-
2204
- this.depths.list = this.depths.list.sort(function(a, b) {
2205
- return a - b;
2206
- });
2283
+ },
2207
2284
 
2208
- return this;
2285
+ // [invokeKnownHelper]
2286
+ //
2287
+ // On stack, before: hash, inverse, program, params..., ...
2288
+ // On stack, after: result of helper invocation
2289
+ //
2290
+ // This operation is used when the helper is known to exist,
2291
+ // so a `helperMissing` fallback is not required.
2292
+ invokeKnownHelper: function(paramSize, name) {
2293
+ var helper = this.setupHelper(paramSize, name);
2294
+ this.push(helper.name + ".call(" + helper.callParams + ")");
2209
2295
  },
2210
2296
 
2211
- compileProgram: function(program) {
2212
- var result = new this.compiler().compile(program, this.options);
2213
- var guid = this.guid++, depth;
2297
+ // [invokeAmbiguous]
2298
+ //
2299
+ // On stack, before: hash, inverse, program, params..., ...
2300
+ // On stack, after: result of disambiguation
2301
+ //
2302
+ // This operation is used when an expression like `{{foo}}`
2303
+ // is provided, but we don't know at compile-time whether it
2304
+ // is a helper or a path.
2305
+ //
2306
+ // This operation emits more code than the other options,
2307
+ // and can be avoided by passing the `knownHelpers` and
2308
+ // `knownHelpersOnly` flags at compile-time.
2309
+ invokeAmbiguous: function(name, helperCall) {
2310
+ this.context.aliases.functionType = '"function"';
2311
+ this.useRegister('helper');
2214
2312
 
2215
- this.usePartial = this.usePartial || result.usePartial;
2313
+ this.emptyHash();
2314
+ var helper = this.setupHelper(0, name, helperCall);
2216
2315
 
2217
- this.children[guid] = result;
2316
+ var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
2218
2317
 
2219
- for(var i=0, l=result.depths.list.length; i<l; i++) {
2220
- depth = result.depths.list[i];
2318
+ var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
2319
+ var nextStack = this.nextStack();
2221
2320
 
2222
- if(depth < 2) { continue; }
2223
- else { this.addDepth(depth - 1); }
2321
+ if (helper.paramsInit) {
2322
+ this.pushSource(helper.paramsInit);
2224
2323
  }
2225
-
2226
- return guid;
2324
+ this.pushSource('if (helper = ' + helperName + ') { ' + nextStack + ' = helper.call(' + helper.callParams + '); }');
2325
+ this.pushSource('else { helper = ' + nonHelper + '; ' + nextStack + ' = typeof helper === functionType ? helper.call(' + helper.callParams + ') : helper; }');
2227
2326
  },
2228
2327
 
2229
- block: function(block) {
2230
- var mustache = block.mustache,
2231
- program = block.program,
2232
- inverse = block.inverse;
2233
-
2234
- if (program) {
2235
- program = this.compileProgram(program);
2236
- }
2328
+ // [invokePartial]
2329
+ //
2330
+ // On stack, before: context, ...
2331
+ // On stack after: result of partial invocation
2332
+ //
2333
+ // This operation pops off a context, invokes a partial with that context,
2334
+ // and pushes the result of the invocation back.
2335
+ invokePartial: function(name) {
2336
+ var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
2237
2337
 
2238
- if (inverse) {
2239
- inverse = this.compileProgram(inverse);
2338
+ if (this.options.data) {
2339
+ params.push("data");
2240
2340
  }
2241
2341
 
2242
- var type = this.classifyMustache(mustache);
2243
-
2244
- if (type === "helper") {
2245
- this.helperMustache(mustache, program, inverse);
2246
- } else if (type === "simple") {
2247
- this.simpleMustache(mustache);
2342
+ this.context.aliases.self = "this";
2343
+ this.push("self.invokePartial(" + params.join(", ") + ")");
2344
+ },
2248
2345
 
2249
- // now that the simple mustache is resolved, we need to
2250
- // evaluate it by executing `blockHelperMissing`
2251
- this.opcode('pushProgram', program);
2252
- this.opcode('pushProgram', inverse);
2253
- this.opcode('emptyHash');
2254
- this.opcode('blockValue');
2255
- } else {
2256
- this.ambiguousMustache(mustache, program, inverse);
2346
+ // [assignToHash]
2347
+ //
2348
+ // On stack, before: value, hash, ...
2349
+ // On stack, after: hash, ...
2350
+ //
2351
+ // Pops a value and hash off the stack, assigns `hash[key] = value`
2352
+ // and pushes the hash back onto the stack.
2353
+ assignToHash: function(key) {
2354
+ var value = this.popStack(),
2355
+ context,
2356
+ type;
2257
2357
 
2258
- // now that the simple mustache is resolved, we need to
2259
- // evaluate it by executing `blockHelperMissing`
2260
- this.opcode('pushProgram', program);
2261
- this.opcode('pushProgram', inverse);
2262
- this.opcode('emptyHash');
2263
- this.opcode('ambiguousBlockValue');
2358
+ if (this.options.stringParams) {
2359
+ type = this.popStack();
2360
+ context = this.popStack();
2264
2361
  }
2265
2362
 
2266
- this.opcode('append');
2363
+ var hash = this.hash;
2364
+ if (context) {
2365
+ hash.contexts.push("'" + key + "': " + context);
2366
+ }
2367
+ if (type) {
2368
+ hash.types.push("'" + key + "': " + type);
2369
+ }
2370
+ hash.values.push("'" + key + "': (" + value + ")");
2267
2371
  },
2268
2372
 
2269
- hash: function(hash) {
2270
- var pairs = hash.pairs, pair, val;
2373
+ // HELPERS
2271
2374
 
2272
- this.opcode('pushHash');
2375
+ compiler: JavaScriptCompiler,
2273
2376
 
2274
- for(var i=0, l=pairs.length; i<l; i++) {
2275
- pair = pairs[i];
2276
- val = pair[1];
2377
+ compileChildren: function(environment, options) {
2378
+ var children = environment.children, child, compiler;
2277
2379
 
2278
- if (this.options.stringParams) {
2279
- if(val.depth) {
2280
- this.addDepth(val.depth);
2281
- }
2282
- this.opcode('getContext', val.depth || 0);
2283
- this.opcode('pushStringParam', val.stringModeValue, val.type);
2380
+ for(var i=0, l=children.length; i<l; i++) {
2381
+ child = children[i];
2382
+ compiler = new this.compiler();
2383
+
2384
+ var index = this.matchExistingProgram(child);
2385
+
2386
+ if (index == null) {
2387
+ this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
2388
+ index = this.context.programs.length;
2389
+ child.index = index;
2390
+ child.name = 'program' + index;
2391
+ this.context.programs[index] = compiler.compile(child, options, this.context);
2392
+ this.context.environments[index] = child;
2284
2393
  } else {
2285
- this.accept(val);
2394
+ child.index = index;
2395
+ child.name = 'program' + index;
2396
+ }
2397
+ }
2398
+ },
2399
+ matchExistingProgram: function(child) {
2400
+ for (var i = 0, len = this.context.environments.length; i < len; i++) {
2401
+ var environment = this.context.environments[i];
2402
+ if (environment && environment.equals(child)) {
2403
+ return i;
2286
2404
  }
2287
-
2288
- this.opcode('assignToHash', pair[0]);
2289
2405
  }
2290
- this.opcode('popHash');
2291
2406
  },
2292
2407
 
2293
- partial: function(partial) {
2294
- var partialName = partial.partialName;
2295
- this.usePartial = true;
2408
+ programExpression: function(guid) {
2409
+ this.context.aliases.self = "this";
2296
2410
 
2297
- if(partial.context) {
2298
- this.ID(partial.context);
2299
- } else {
2300
- this.opcode('push', 'depth0');
2411
+ if(guid == null) {
2412
+ return "self.noop";
2301
2413
  }
2302
2414
 
2303
- this.opcode('invokePartial', partialName.name);
2304
- this.opcode('append');
2305
- },
2415
+ var child = this.environment.children[guid],
2416
+ depths = child.depths.list, depth;
2306
2417
 
2307
- content: function(content) {
2308
- this.opcode('appendContent', content.string);
2309
- },
2418
+ var programParams = [child.index, child.name, "data"];
2310
2419
 
2311
- mustache: function(mustache) {
2312
- var options = this.options;
2313
- var type = this.classifyMustache(mustache);
2420
+ for(var i=0, l = depths.length; i<l; i++) {
2421
+ depth = depths[i];
2314
2422
 
2315
- if (type === "simple") {
2316
- this.simpleMustache(mustache);
2317
- } else if (type === "helper") {
2318
- this.helperMustache(mustache);
2319
- } else {
2320
- this.ambiguousMustache(mustache);
2423
+ if(depth === 1) { programParams.push("depth0"); }
2424
+ else { programParams.push("depth" + (depth - 1)); }
2321
2425
  }
2322
2426
 
2323
- if(mustache.escaped && !options.noEscape) {
2324
- this.opcode('appendEscaped');
2325
- } else {
2326
- this.opcode('append');
2327
- }
2427
+ return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")";
2328
2428
  },
2329
2429
 
2330
- ambiguousMustache: function(mustache, program, inverse) {
2331
- var id = mustache.id,
2332
- name = id.parts[0],
2333
- isBlock = program != null || inverse != null;
2334
-
2335
- this.opcode('getContext', id.depth);
2430
+ register: function(name, val) {
2431
+ this.useRegister(name);
2432
+ this.pushSource(name + " = " + val + ";");
2433
+ },
2336
2434
 
2337
- this.opcode('pushProgram', program);
2338
- this.opcode('pushProgram', inverse);
2435
+ useRegister: function(name) {
2436
+ if(!this.registers[name]) {
2437
+ this.registers[name] = true;
2438
+ this.registers.list.push(name);
2439
+ }
2440
+ },
2339
2441
 
2340
- this.opcode('invokeAmbiguous', name, isBlock);
2442
+ pushStackLiteral: function(item) {
2443
+ return this.push(new Literal(item));
2341
2444
  },
2342
2445
 
2343
- simpleMustache: function(mustache) {
2344
- var id = mustache.id;
2446
+ pushSource: function(source) {
2447
+ if (this.pendingContent) {
2448
+ this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent)));
2449
+ this.pendingContent = undefined;
2450
+ }
2345
2451
 
2346
- if (id.type === 'DATA') {
2347
- this.DATA(id);
2348
- } else if (id.parts.length) {
2349
- this.ID(id);
2350
- } else {
2351
- // Simplified ID for `this`
2352
- this.addDepth(id.depth);
2353
- this.opcode('getContext', id.depth);
2354
- this.opcode('pushContext');
2452
+ if (source) {
2453
+ this.source.push(source);
2355
2454
  }
2455
+ },
2356
2456
 
2357
- this.opcode('resolvePossibleLambda');
2457
+ pushStack: function(item) {
2458
+ this.flushInline();
2459
+
2460
+ var stack = this.incrStack();
2461
+ if (item) {
2462
+ this.pushSource(stack + " = " + item + ";");
2463
+ }
2464
+ this.compileStack.push(stack);
2465
+ return stack;
2358
2466
  },
2359
2467
 
2360
- helperMustache: function(mustache, program, inverse) {
2361
- var params = this.setupFullMustacheParams(mustache, program, inverse),
2362
- name = mustache.id.parts[0];
2468
+ replaceStack: function(callback) {
2469
+ var prefix = '',
2470
+ inline = this.isInline(),
2471
+ stack,
2472
+ createdStack,
2473
+ usedLiteral;
2474
+
2475
+ // If we are currently inline then we want to merge the inline statement into the
2476
+ // replacement statement via ','
2477
+ if (inline) {
2478
+ var top = this.popStack(true);
2479
+
2480
+ if (top instanceof Literal) {
2481
+ // Literals do not need to be inlined
2482
+ stack = top.value;
2483
+ usedLiteral = true;
2484
+ } else {
2485
+ // Get or create the current stack name for use by the inline
2486
+ createdStack = !this.stackSlot;
2487
+ var name = !createdStack ? this.topStackName() : this.incrStack();
2363
2488
 
2364
- if (this.options.knownHelpers[name]) {
2365
- this.opcode('invokeKnownHelper', params.length, name);
2366
- } else if (this.options.knownHelpersOnly) {
2367
- throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
2489
+ prefix = '(' + this.push(name) + ' = ' + top + '),';
2490
+ stack = this.topStack();
2491
+ }
2368
2492
  } else {
2369
- this.opcode('invokeHelper', params.length, name);
2493
+ stack = this.topStack();
2370
2494
  }
2371
- },
2372
2495
 
2373
- ID: function(id) {
2374
- this.addDepth(id.depth);
2375
- this.opcode('getContext', id.depth);
2496
+ var item = callback.call(this, stack);
2376
2497
 
2377
- var name = id.parts[0];
2378
- if (!name) {
2379
- this.opcode('pushContext');
2498
+ if (inline) {
2499
+ if (!usedLiteral) {
2500
+ this.popStack();
2501
+ }
2502
+ if (createdStack) {
2503
+ this.stackSlot--;
2504
+ }
2505
+ this.push('(' + prefix + item + ')');
2380
2506
  } else {
2381
- this.opcode('lookupOnContext', id.parts[0]);
2382
- }
2507
+ // Prevent modification of the context depth variable. Through replaceStack
2508
+ if (!/^stack/.test(stack)) {
2509
+ stack = this.nextStack();
2510
+ }
2383
2511
 
2384
- for(var i=1, l=id.parts.length; i<l; i++) {
2385
- this.opcode('lookup', id.parts[i]);
2512
+ this.pushSource(stack + " = (" + prefix + item + ");");
2386
2513
  }
2514
+ return stack;
2387
2515
  },
2388
2516
 
2389
- DATA: function(data) {
2390
- this.options.data = true;
2391
- if (data.id.isScoped || data.id.depth) {
2392
- throw new Exception('Scoped data references are not supported: ' + data.original);
2393
- }
2517
+ nextStack: function() {
2518
+ return this.pushStack();
2519
+ },
2394
2520
 
2395
- this.opcode('lookupData');
2396
- var parts = data.id.parts;
2397
- for(var i=0, l=parts.length; i<l; i++) {
2398
- this.opcode('lookup', parts[i]);
2521
+ incrStack: function() {
2522
+ this.stackSlot++;
2523
+ if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
2524
+ return this.topStackName();
2525
+ },
2526
+ topStackName: function() {
2527
+ return "stack" + this.stackSlot;
2528
+ },
2529
+ flushInline: function() {
2530
+ var inlineStack = this.inlineStack;
2531
+ if (inlineStack.length) {
2532
+ this.inlineStack = [];
2533
+ for (var i = 0, len = inlineStack.length; i < len; i++) {
2534
+ var entry = inlineStack[i];
2535
+ if (entry instanceof Literal) {
2536
+ this.compileStack.push(entry);
2537
+ } else {
2538
+ this.pushStack(entry);
2539
+ }
2540
+ }
2399
2541
  }
2400
2542
  },
2401
-
2402
- STRING: function(string) {
2403
- this.opcode('pushString', string.string);
2543
+ isInline: function() {
2544
+ return this.inlineStack.length;
2404
2545
  },
2405
2546
 
2406
- INTEGER: function(integer) {
2407
- this.opcode('pushLiteral', integer.integer);
2408
- },
2547
+ popStack: function(wrapped) {
2548
+ var inline = this.isInline(),
2549
+ item = (inline ? this.inlineStack : this.compileStack).pop();
2409
2550
 
2410
- BOOLEAN: function(bool) {
2411
- this.opcode('pushLiteral', bool.bool);
2551
+ if (!wrapped && (item instanceof Literal)) {
2552
+ return item.value;
2553
+ } else {
2554
+ if (!inline) {
2555
+ if (!this.stackSlot) {
2556
+ throw new Exception('Invalid stack pop');
2557
+ }
2558
+ this.stackSlot--;
2559
+ }
2560
+ return item;
2561
+ }
2412
2562
  },
2413
2563
 
2414
- comment: function() {},
2564
+ topStack: function(wrapped) {
2565
+ var stack = (this.isInline() ? this.inlineStack : this.compileStack),
2566
+ item = stack[stack.length - 1];
2415
2567
 
2416
- // HELPERS
2417
- opcode: function(name) {
2418
- this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
2568
+ if (!wrapped && (item instanceof Literal)) {
2569
+ return item.value;
2570
+ } else {
2571
+ return item;
2572
+ }
2419
2573
  },
2420
2574
 
2421
- declare: function(name, value) {
2422
- this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
2575
+ quotedString: function(str) {
2576
+ return '"' + str
2577
+ .replace(/\\/g, '\\\\')
2578
+ .replace(/"/g, '\\"')
2579
+ .replace(/\n/g, '\\n')
2580
+ .replace(/\r/g, '\\r')
2581
+ .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
2582
+ .replace(/\u2029/g, '\\u2029') + '"';
2423
2583
  },
2424
2584
 
2425
- addDepth: function(depth) {
2426
- if(isNaN(depth)) { throw new Error("EWOT"); }
2427
- if(depth === 0) { return; }
2585
+ setupHelper: function(paramSize, name, missingParams) {
2586
+ var params = [],
2587
+ paramsInit = this.setupParams(paramSize, params, missingParams);
2588
+ var foundHelper = this.nameLookup('helpers', name, 'helper');
2428
2589
 
2429
- if(!this.depths[depth]) {
2430
- this.depths[depth] = true;
2431
- this.depths.list.push(depth);
2432
- }
2590
+ return {
2591
+ params: params,
2592
+ paramsInit: paramsInit,
2593
+ name: foundHelper,
2594
+ callParams: ["depth0"].concat(params).join(", "),
2595
+ helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
2596
+ };
2433
2597
  },
2434
2598
 
2435
- classifyMustache: function(mustache) {
2436
- var isHelper = mustache.isHelper;
2437
- var isEligible = mustache.eligibleHelper;
2438
- var options = this.options;
2599
+ setupOptions: function(paramSize, params) {
2600
+ var options = [], contexts = [], types = [], param, inverse, program;
2439
2601
 
2440
- // if ambiguous, we can possibly resolve the ambiguity now
2441
- if (isEligible && !isHelper) {
2442
- var name = mustache.id.parts[0];
2602
+ options.push("hash:" + this.popStack());
2443
2603
 
2444
- if (options.knownHelpers[name]) {
2445
- isHelper = true;
2446
- } else if (options.knownHelpersOnly) {
2447
- isEligible = false;
2448
- }
2604
+ if (this.options.stringParams) {
2605
+ options.push("hashTypes:" + this.popStack());
2606
+ options.push("hashContexts:" + this.popStack());
2449
2607
  }
2450
2608
 
2451
- if (isHelper) { return "helper"; }
2452
- else if (isEligible) { return "ambiguous"; }
2453
- else { return "simple"; }
2454
- },
2609
+ inverse = this.popStack();
2610
+ program = this.popStack();
2455
2611
 
2456
- pushParams: function(params) {
2457
- var i = params.length, param;
2612
+ // Avoid setting fn and inverse if neither are set. This allows
2613
+ // helpers to do a check for `if (options.fn)`
2614
+ if (program || inverse) {
2615
+ if (!program) {
2616
+ this.context.aliases.self = "this";
2617
+ program = "self.noop";
2618
+ }
2458
2619
 
2459
- while(i--) {
2460
- param = params[i];
2620
+ if (!inverse) {
2621
+ this.context.aliases.self = "this";
2622
+ inverse = "self.noop";
2623
+ }
2461
2624
 
2462
- if(this.options.stringParams) {
2463
- if(param.depth) {
2464
- this.addDepth(param.depth);
2465
- }
2625
+ options.push("inverse:" + inverse);
2626
+ options.push("fn:" + program);
2627
+ }
2466
2628
 
2467
- this.opcode('getContext', param.depth || 0);
2468
- this.opcode('pushStringParam', param.stringModeValue, param.type);
2469
- } else {
2470
- this[param.type](param);
2629
+ for(var i=0; i<paramSize; i++) {
2630
+ param = this.popStack();
2631
+ params.push(param);
2632
+
2633
+ if(this.options.stringParams) {
2634
+ types.push(this.popStack());
2635
+ contexts.push(this.popStack());
2471
2636
  }
2472
2637
  }
2473
- },
2474
2638
 
2475
- setupMustacheParams: function(mustache) {
2476
- var params = mustache.params;
2477
- this.pushParams(params);
2639
+ if (this.options.stringParams) {
2640
+ options.push("contexts:[" + contexts.join(",") + "]");
2641
+ options.push("types:[" + types.join(",") + "]");
2642
+ }
2478
2643
 
2479
- if(mustache.hash) {
2480
- this.hash(mustache.hash);
2481
- } else {
2482
- this.opcode('emptyHash');
2644
+ if(this.options.data) {
2645
+ options.push("data:data");
2483
2646
  }
2484
2647
 
2485
- return params;
2648
+ return options;
2486
2649
  },
2487
2650
 
2488
- // this will replace setupMustacheParams when we're done
2489
- setupFullMustacheParams: function(mustache, program, inverse) {
2490
- var params = mustache.params;
2491
- this.pushParams(params);
2492
-
2493
- this.opcode('pushProgram', program);
2494
- this.opcode('pushProgram', inverse);
2651
+ // the params and contexts arguments are passed in arrays
2652
+ // to fill in
2653
+ setupParams: function(paramSize, params, useRegister) {
2654
+ var options = '{' + this.setupOptions(paramSize, params).join(',') + '}';
2495
2655
 
2496
- if(mustache.hash) {
2497
- this.hash(mustache.hash);
2656
+ if (useRegister) {
2657
+ this.useRegister('options');
2658
+ params.push('options');
2659
+ return 'options=' + options;
2498
2660
  } else {
2499
- this.opcode('emptyHash');
2661
+ params.push(options);
2662
+ return '';
2500
2663
  }
2501
-
2502
- return params;
2503
2664
  }
2504
2665
  };
2505
2666
 
2506
- function precompile(input, options) {
2507
- if (input == null || (typeof input !== 'string' && input.constructor !== AST.ProgramNode)) {
2508
- throw new Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
2509
- }
2667
+ var reservedWords = (
2668
+ "break else new var" +
2669
+ " case finally return void" +
2670
+ " catch for switch while" +
2671
+ " continue function this with" +
2672
+ " default if throw" +
2673
+ " delete in try" +
2674
+ " do instanceof typeof" +
2675
+ " abstract enum int short" +
2676
+ " boolean export interface static" +
2677
+ " byte extends long super" +
2678
+ " char final native synchronized" +
2679
+ " class float package throws" +
2680
+ " const goto private transient" +
2681
+ " debugger implements protected volatile" +
2682
+ " double import public let yield"
2683
+ ).split(" ");
2510
2684
 
2511
- options = options || {};
2512
- if (!('data' in options)) {
2513
- options.data = true;
2514
- }
2685
+ var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
2515
2686
 
2516
- var ast = parse(input);
2517
- var environment = new Compiler().compile(ast, options);
2518
- return new JavaScriptCompiler().compile(environment, options);
2687
+ for(var i=0, l=reservedWords.length; i<l; i++) {
2688
+ compilerWords[reservedWords[i]] = true;
2519
2689
  }
2520
2690
 
2521
- __exports__.precompile = precompile;function compile(input, options, env) {
2522
- if (input == null || (typeof input !== 'string' && input.constructor !== AST.ProgramNode)) {
2523
- throw new Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
2524
- }
2525
-
2526
- options = options || {};
2527
-
2528
- if (!('data' in options)) {
2529
- options.data = true;
2530
- }
2531
-
2532
- var compiled;
2533
-
2534
- function compileInput() {
2535
- var ast = parse(input);
2536
- var environment = new Compiler().compile(ast, options);
2537
- var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true);
2538
- return env.template(templateSpec);
2691
+ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
2692
+ if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) {
2693
+ return true;
2539
2694
  }
2695
+ return false;
2696
+ };
2540
2697
 
2541
- // Template is only compiled on first use and cached after that point.
2542
- return function(context, options) {
2543
- if (!compiled) {
2544
- compiled = compileInput();
2545
- }
2546
- return compiled.call(this, context, options);
2547
- };
2548
- }
2549
-
2550
- __exports__.compile = compile;
2698
+ __exports__ = JavaScriptCompiler;
2551
2699
  return __exports__;
2552
- })(__module5__, __module8__, __module11__, __module7__);
2700
+ })(__module2__, __module5__);
2553
2701
 
2554
2702
  // handlebars.js
2555
2703
  var __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {
2556
2704
  "use strict";
2557
2705
  var __exports__;
2706
+ /*globals Handlebars: true */
2558
2707
  var Handlebars = __dependency1__;
2559
2708
 
2560
2709
  // Compiler imports
@@ -2573,7 +2722,9 @@ var __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, _
2573
2722
  hb.compile = function(input, options) {
2574
2723
  return compile(input, options, hb);
2575
2724
  };
2576
- hb.precompile = precompile;
2725
+ hb.precompile = function (input, options) {
2726
+ return precompile(input, options, hb);
2727
+ };
2577
2728
 
2578
2729
  hb.AST = AST;
2579
2730
  hb.Compiler = Compiler;