handlebars-source 1.0.0.rc2 → 1.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (3) hide show
  1. data/dist/handlebars.js +1158 -1159
  2. data/dist/handlebars.runtime.js +50 -55
  3. metadata +1 -1
@@ -22,19 +22,19 @@ THE SOFTWARE.
22
22
 
23
23
  */
24
24
 
25
- // lib/handlebars/base.js
26
-
27
- /*jshint eqnull:true*/
28
- this.Handlebars = {};
25
+ // lib/handlebars/browser-prefix.js
26
+ var Handlebars = {};
29
27
 
30
- (function(Handlebars) {
28
+ (function(Handlebars, undefined) {
29
+ ;
30
+ // lib/handlebars/base.js
31
31
 
32
- Handlebars.VERSION = "1.0.rc.2";
32
+ Handlebars.VERSION = "1.0.0-rc.3";
33
33
  Handlebars.COMPILER_REVISION = 2;
34
34
 
35
35
  Handlebars.REVISION_CHANGES = {
36
36
  1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
37
- 2: '>= 1.0.rc.3'
37
+ 2: '>= 1.0.0-rc.3'
38
38
  };
39
39
 
40
40
  Handlebars.helpers = {};
@@ -62,8 +62,6 @@ var toString = Object.prototype.toString, functionType = "[object Function]";
62
62
  Handlebars.registerHelper('blockHelperMissing', function(context, options) {
63
63
  var inverse = options.inverse || function() {}, fn = options.fn;
64
64
 
65
-
66
- var ret = "";
67
65
  var type = toString.call(context);
68
66
 
69
67
  if(type === functionType) { context = context.call(this); }
@@ -154,11 +152,7 @@ Handlebars.registerHelper('if', function(context, options) {
154
152
  });
155
153
 
156
154
  Handlebars.registerHelper('unless', function(context, options) {
157
- var fn = options.fn, inverse = options.inverse;
158
- options.fn = inverse;
159
- options.inverse = fn;
160
-
161
- return Handlebars.helpers['if'].call(this, context, options);
155
+ return Handlebars.helpers['if'].call(this, context, {fn: options.inverse, inverse: options.fn});
162
156
  });
163
157
 
164
158
  Handlebars.registerHelper('with', function(context, options) {
@@ -169,8 +163,6 @@ Handlebars.registerHelper('log', function(context, options) {
169
163
  var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
170
164
  Handlebars.log(level, context);
171
165
  });
172
-
173
- }(this.Handlebars));
174
166
  ;
175
167
  // lib/handlebars/compiler/parser.js
176
168
  /* Jison generated parser */
@@ -638,7 +630,7 @@ case 32: return 5;
638
630
  break;
639
631
  }
640
632
  };
641
- lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/];
633
+ lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/];
642
634
  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,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"par":{"rules":[30,31],"inclusive":false},"INITIAL":{"rules":[0,1,32],"inclusive":true}};
643
635
  return lexer;})()
644
636
  parser.lexer = lexer;
@@ -646,6 +638,7 @@ function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Pa
646
638
  return new Parser;
647
639
  })();;
648
640
  // lib/handlebars/compiler/base.js
641
+
649
642
  Handlebars.Parser = handlebars;
650
643
 
651
644
  Handlebars.parse = function(input) {
@@ -656,139 +649,133 @@ Handlebars.parse = function(input) {
656
649
  Handlebars.Parser.yy = Handlebars.AST;
657
650
  return Handlebars.Parser.parse(input);
658
651
  };
659
-
660
- Handlebars.print = function(ast) {
661
- return new Handlebars.PrintVisitor().accept(ast);
662
- };;
652
+ ;
663
653
  // lib/handlebars/compiler/ast.js
664
- (function() {
654
+ Handlebars.AST = {};
665
655
 
666
- Handlebars.AST = {};
667
-
668
- Handlebars.AST.ProgramNode = function(statements, inverse) {
669
- this.type = "program";
670
- this.statements = statements;
671
- if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
672
- };
656
+ Handlebars.AST.ProgramNode = function(statements, inverse) {
657
+ this.type = "program";
658
+ this.statements = statements;
659
+ if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
660
+ };
673
661
 
674
- Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
675
- this.type = "mustache";
676
- this.escaped = !unescaped;
677
- this.hash = hash;
662
+ Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
663
+ this.type = "mustache";
664
+ this.escaped = !unescaped;
665
+ this.hash = hash;
678
666
 
679
- var id = this.id = rawParams[0];
680
- var params = this.params = rawParams.slice(1);
667
+ var id = this.id = rawParams[0];
668
+ var params = this.params = rawParams.slice(1);
681
669
 
682
- // a mustache is an eligible helper if:
683
- // * its id is simple (a single part, not `this` or `..`)
684
- var eligibleHelper = this.eligibleHelper = id.isSimple;
670
+ // a mustache is an eligible helper if:
671
+ // * its id is simple (a single part, not `this` or `..`)
672
+ var eligibleHelper = this.eligibleHelper = id.isSimple;
685
673
 
686
- // a mustache is definitely a helper if:
687
- // * it is an eligible helper, and
688
- // * it has at least one parameter or hash segment
689
- this.isHelper = eligibleHelper && (params.length || hash);
674
+ // a mustache is definitely a helper if:
675
+ // * it is an eligible helper, and
676
+ // * it has at least one parameter or hash segment
677
+ this.isHelper = eligibleHelper && (params.length || hash);
690
678
 
691
- // if a mustache is an eligible helper but not a definite
692
- // helper, it is ambiguous, and will be resolved in a later
693
- // pass or at runtime.
694
- };
679
+ // if a mustache is an eligible helper but not a definite
680
+ // helper, it is ambiguous, and will be resolved in a later
681
+ // pass or at runtime.
682
+ };
695
683
 
696
- Handlebars.AST.PartialNode = function(partialName, context) {
697
- this.type = "partial";
698
- this.partialName = partialName;
699
- this.context = context;
700
- };
684
+ Handlebars.AST.PartialNode = function(partialName, context) {
685
+ this.type = "partial";
686
+ this.partialName = partialName;
687
+ this.context = context;
688
+ };
701
689
 
690
+ Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
702
691
  var verifyMatch = function(open, close) {
703
692
  if(open.original !== close.original) {
704
693
  throw new Handlebars.Exception(open.original + " doesn't match " + close.original);
705
694
  }
706
695
  };
707
696
 
708
- Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
709
- verifyMatch(mustache.id, close);
710
- this.type = "block";
711
- this.mustache = mustache;
712
- this.program = program;
713
- this.inverse = inverse;
697
+ verifyMatch(mustache.id, close);
698
+ this.type = "block";
699
+ this.mustache = mustache;
700
+ this.program = program;
701
+ this.inverse = inverse;
714
702
 
715
- if (this.inverse && !this.program) {
716
- this.isInverse = true;
717
- }
718
- };
703
+ if (this.inverse && !this.program) {
704
+ this.isInverse = true;
705
+ }
706
+ };
719
707
 
720
- Handlebars.AST.ContentNode = function(string) {
721
- this.type = "content";
722
- this.string = string;
723
- };
708
+ Handlebars.AST.ContentNode = function(string) {
709
+ this.type = "content";
710
+ this.string = string;
711
+ };
724
712
 
725
- Handlebars.AST.HashNode = function(pairs) {
726
- this.type = "hash";
727
- this.pairs = pairs;
728
- };
713
+ Handlebars.AST.HashNode = function(pairs) {
714
+ this.type = "hash";
715
+ this.pairs = pairs;
716
+ };
729
717
 
730
- Handlebars.AST.IdNode = function(parts) {
731
- this.type = "ID";
732
- this.original = parts.join(".");
718
+ Handlebars.AST.IdNode = function(parts) {
719
+ this.type = "ID";
720
+ this.original = parts.join(".");
733
721
 
734
- var dig = [], depth = 0;
722
+ var dig = [], depth = 0;
735
723
 
736
- for(var i=0,l=parts.length; i<l; i++) {
737
- var part = parts[i];
724
+ for(var i=0,l=parts.length; i<l; i++) {
725
+ var part = parts[i];
738
726
 
739
- if (part === ".." || part === "." || part === "this") {
740
- if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + this.original); }
741
- else if (part === "..") { depth++; }
742
- else { this.isScoped = true; }
743
- }
744
- else { dig.push(part); }
727
+ if (part === ".." || part === "." || part === "this") {
728
+ if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + this.original); }
729
+ else if (part === "..") { depth++; }
730
+ else { this.isScoped = true; }
745
731
  }
732
+ else { dig.push(part); }
733
+ }
746
734
 
747
- this.parts = dig;
748
- this.string = dig.join('.');
749
- this.depth = depth;
750
-
751
- // an ID is simple if it only has one part, and that part is not
752
- // `..` or `this`.
753
- this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
735
+ this.parts = dig;
736
+ this.string = dig.join('.');
737
+ this.depth = depth;
754
738
 
755
- this.stringModeValue = this.string;
756
- };
739
+ // an ID is simple if it only has one part, and that part is not
740
+ // `..` or `this`.
741
+ this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
757
742
 
758
- Handlebars.AST.PartialNameNode = function(name) {
759
- this.type = "PARTIAL_NAME";
760
- this.name = name;
761
- };
743
+ this.stringModeValue = this.string;
744
+ };
762
745
 
763
- Handlebars.AST.DataNode = function(id) {
764
- this.type = "DATA";
765
- this.id = id;
766
- };
746
+ Handlebars.AST.PartialNameNode = function(name) {
747
+ this.type = "PARTIAL_NAME";
748
+ this.name = name;
749
+ };
767
750
 
768
- Handlebars.AST.StringNode = function(string) {
769
- this.type = "STRING";
770
- this.string = string;
771
- this.stringModeValue = string;
772
- };
751
+ Handlebars.AST.DataNode = function(id) {
752
+ this.type = "DATA";
753
+ this.id = id;
754
+ };
773
755
 
774
- Handlebars.AST.IntegerNode = function(integer) {
775
- this.type = "INTEGER";
776
- this.integer = integer;
777
- this.stringModeValue = Number(integer);
778
- };
756
+ Handlebars.AST.StringNode = function(string) {
757
+ this.type = "STRING";
758
+ this.string = string;
759
+ this.stringModeValue = string;
760
+ };
779
761
 
780
- Handlebars.AST.BooleanNode = function(bool) {
781
- this.type = "BOOLEAN";
782
- this.bool = bool;
783
- this.stringModeValue = bool === "true";
784
- };
762
+ Handlebars.AST.IntegerNode = function(integer) {
763
+ this.type = "INTEGER";
764
+ this.integer = integer;
765
+ this.stringModeValue = Number(integer);
766
+ };
785
767
 
786
- Handlebars.AST.CommentNode = function(comment) {
787
- this.type = "comment";
788
- this.comment = comment;
789
- };
768
+ Handlebars.AST.BooleanNode = function(bool) {
769
+ this.type = "BOOLEAN";
770
+ this.bool = bool;
771
+ this.stringModeValue = bool === "true";
772
+ };
790
773
 
791
- })();;
774
+ Handlebars.AST.CommentNode = function(comment) {
775
+ this.type = "comment";
776
+ this.comment = comment;
777
+ };
778
+ ;
792
779
  // lib/handlebars/utils.js
793
780
 
794
781
  var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
@@ -811,1273 +798,1280 @@ Handlebars.SafeString.prototype.toString = function() {
811
798
  return this.string.toString();
812
799
  };
813
800
 
814
- (function() {
815
- var escape = {
816
- "&": "&amp;",
817
- "<": "&lt;",
818
- ">": "&gt;",
819
- '"': "&quot;",
820
- "'": "&#x27;",
821
- "`": "&#x60;"
822
- };
801
+ var escape = {
802
+ "&": "&amp;",
803
+ "<": "&lt;",
804
+ ">": "&gt;",
805
+ '"': "&quot;",
806
+ "'": "&#x27;",
807
+ "`": "&#x60;"
808
+ };
823
809
 
824
- var badChars = /[&<>"'`]/g;
825
- var possible = /[&<>"'`]/;
810
+ var badChars = /[&<>"'`]/g;
811
+ var possible = /[&<>"'`]/;
826
812
 
827
- var escapeChar = function(chr) {
828
- return escape[chr] || "&amp;";
829
- };
813
+ var escapeChar = function(chr) {
814
+ return escape[chr] || "&amp;";
815
+ };
830
816
 
831
- Handlebars.Utils = {
832
- escapeExpression: function(string) {
833
- // don't escape SafeStrings, since they're already safe
834
- if (string instanceof Handlebars.SafeString) {
835
- return string.toString();
836
- } else if (string == null || string === false) {
837
- return "";
838
- }
817
+ Handlebars.Utils = {
818
+ escapeExpression: function(string) {
819
+ // don't escape SafeStrings, since they're already safe
820
+ if (string instanceof Handlebars.SafeString) {
821
+ return string.toString();
822
+ } else if (string == null || string === false) {
823
+ return "";
824
+ }
839
825
 
840
- if(!possible.test(string)) { return string; }
841
- return string.replace(badChars, escapeChar);
842
- },
826
+ if(!possible.test(string)) { return string; }
827
+ return string.replace(badChars, escapeChar);
828
+ },
843
829
 
844
- isEmpty: function(value) {
845
- if (!value && value !== 0) {
846
- return true;
847
- } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
848
- return true;
849
- } else {
850
- return false;
851
- }
830
+ isEmpty: function(value) {
831
+ if (!value && value !== 0) {
832
+ return true;
833
+ } else if(toString.call(value) === "[object Array]" && value.length === 0) {
834
+ return true;
835
+ } else {
836
+ return false;
852
837
  }
853
- };
854
- })();;
838
+ }
839
+ };
840
+ ;
855
841
  // lib/handlebars/compiler/compiler.js
856
842
 
857
843
  /*jshint eqnull:true*/
858
- Handlebars.Compiler = function() {};
859
- Handlebars.JavaScriptCompiler = function() {};
844
+ var Compiler = Handlebars.Compiler = function() {};
845
+ var JavaScriptCompiler = Handlebars.JavaScriptCompiler = function() {};
860
846
 
861
- (function(Compiler, JavaScriptCompiler) {
862
- // the foundHelper register will disambiguate helper lookup from finding a
863
- // function in a context. This is necessary for mustache compatibility, which
864
- // requires that context functions in blocks are evaluated by blockHelperMissing,
865
- // and then proceed as if the resulting value was provided to blockHelperMissing.
847
+ // the foundHelper register will disambiguate helper lookup from finding a
848
+ // function in a context. This is necessary for mustache compatibility, which
849
+ // requires that context functions in blocks are evaluated by blockHelperMissing,
850
+ // and then proceed as if the resulting value was provided to blockHelperMissing.
866
851
 
867
- Compiler.prototype = {
868
- compiler: Compiler,
852
+ Compiler.prototype = {
853
+ compiler: Compiler,
869
854
 
870
- disassemble: function() {
871
- var opcodes = this.opcodes, opcode, out = [], params, param;
855
+ disassemble: function() {
856
+ var opcodes = this.opcodes, opcode, out = [], params, param;
872
857
 
873
- for (var i=0, l=opcodes.length; i<l; i++) {
874
- opcode = opcodes[i];
858
+ for (var i=0, l=opcodes.length; i<l; i++) {
859
+ opcode = opcodes[i];
875
860
 
876
- if (opcode.opcode === 'DECLARE') {
877
- out.push("DECLARE " + opcode.name + "=" + opcode.value);
878
- } else {
879
- params = [];
880
- for (var j=0; j<opcode.args.length; j++) {
881
- param = opcode.args[j];
882
- if (typeof param === "string") {
883
- param = "\"" + param.replace("\n", "\\n") + "\"";
884
- }
885
- params.push(param);
861
+ if (opcode.opcode === 'DECLARE') {
862
+ out.push("DECLARE " + opcode.name + "=" + opcode.value);
863
+ } else {
864
+ params = [];
865
+ for (var j=0; j<opcode.args.length; j++) {
866
+ param = opcode.args[j];
867
+ if (typeof param === "string") {
868
+ param = "\"" + param.replace("\n", "\\n") + "\"";
886
869
  }
887
- out.push(opcode.opcode + " " + params.join(" "));
870
+ params.push(param);
888
871
  }
872
+ out.push(opcode.opcode + " " + params.join(" "));
889
873
  }
874
+ }
890
875
 
891
- return out.join("\n");
892
- },
893
- equals: function(other) {
894
- var len = this.opcodes.length;
895
- if (other.opcodes.length !== len) {
876
+ return out.join("\n");
877
+ },
878
+ equals: function(other) {
879
+ var len = this.opcodes.length;
880
+ if (other.opcodes.length !== len) {
881
+ return false;
882
+ }
883
+
884
+ for (var i = 0; i < len; i++) {
885
+ var opcode = this.opcodes[i],
886
+ otherOpcode = other.opcodes[i];
887
+ if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
896
888
  return false;
897
889
  }
898
-
899
- for (var i = 0; i < len; i++) {
900
- var opcode = this.opcodes[i],
901
- otherOpcode = other.opcodes[i];
902
- if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
890
+ for (var j = 0; j < opcode.args.length; j++) {
891
+ if (opcode.args[j] !== otherOpcode.args[j]) {
903
892
  return false;
904
893
  }
905
- for (var j = 0; j < opcode.args.length; j++) {
906
- if (opcode.args[j] !== otherOpcode.args[j]) {
907
- return false;
908
- }
909
- }
910
894
  }
911
- return true;
912
- },
895
+ }
913
896
 
914
- guid: 0,
915
-
916
- compile: function(program, options) {
917
- this.children = [];
918
- this.depths = {list: []};
919
- this.options = options;
920
-
921
- // These changes will propagate to the other compiler components
922
- var knownHelpers = this.options.knownHelpers;
923
- this.options.knownHelpers = {
924
- 'helperMissing': true,
925
- 'blockHelperMissing': true,
926
- 'each': true,
927
- 'if': true,
928
- 'unless': true,
929
- 'with': true,
930
- 'log': true
931
- };
932
- if (knownHelpers) {
933
- for (var name in knownHelpers) {
934
- this.options.knownHelpers[name] = knownHelpers[name];
935
- }
897
+ len = this.children.length;
898
+ if (other.children.length !== len) {
899
+ return false;
900
+ }
901
+ for (i = 0; i < len; i++) {
902
+ if (!this.children[i].equals(other.children[i])) {
903
+ return false;
936
904
  }
905
+ }
937
906
 
938
- return this.program(program);
939
- },
907
+ return true;
908
+ },
940
909
 
941
- accept: function(node) {
942
- return this[node.type](node);
943
- },
910
+ guid: 0,
911
+
912
+ compile: function(program, options) {
913
+ this.children = [];
914
+ this.depths = {list: []};
915
+ this.options = options;
916
+
917
+ // These changes will propagate to the other compiler components
918
+ var knownHelpers = this.options.knownHelpers;
919
+ this.options.knownHelpers = {
920
+ 'helperMissing': true,
921
+ 'blockHelperMissing': true,
922
+ 'each': true,
923
+ 'if': true,
924
+ 'unless': true,
925
+ 'with': true,
926
+ 'log': true
927
+ };
928
+ if (knownHelpers) {
929
+ for (var name in knownHelpers) {
930
+ this.options.knownHelpers[name] = knownHelpers[name];
931
+ }
932
+ }
944
933
 
945
- program: function(program) {
946
- var statements = program.statements, statement;
947
- this.opcodes = [];
934
+ return this.program(program);
935
+ },
948
936
 
949
- for(var i=0, l=statements.length; i<l; i++) {
950
- statement = statements[i];
951
- this[statement.type](statement);
952
- }
953
- this.isSimple = l === 1;
937
+ accept: function(node) {
938
+ return this[node.type](node);
939
+ },
954
940
 
955
- this.depths.list = this.depths.list.sort(function(a, b) {
956
- return a - b;
957
- });
941
+ program: function(program) {
942
+ var statements = program.statements, statement;
943
+ this.opcodes = [];
958
944
 
959
- return this;
960
- },
945
+ for(var i=0, l=statements.length; i<l; i++) {
946
+ statement = statements[i];
947
+ this[statement.type](statement);
948
+ }
949
+ this.isSimple = l === 1;
961
950
 
962
- compileProgram: function(program) {
963
- var result = new this.compiler().compile(program, this.options);
964
- var guid = this.guid++, depth;
951
+ this.depths.list = this.depths.list.sort(function(a, b) {
952
+ return a - b;
953
+ });
965
954
 
966
- this.usePartial = this.usePartial || result.usePartial;
955
+ return this;
956
+ },
967
957
 
968
- this.children[guid] = result;
958
+ compileProgram: function(program) {
959
+ var result = new this.compiler().compile(program, this.options);
960
+ var guid = this.guid++, depth;
969
961
 
970
- for(var i=0, l=result.depths.list.length; i<l; i++) {
971
- depth = result.depths.list[i];
962
+ this.usePartial = this.usePartial || result.usePartial;
972
963
 
973
- if(depth < 2) { continue; }
974
- else { this.addDepth(depth - 1); }
975
- }
964
+ this.children[guid] = result;
976
965
 
977
- return guid;
978
- },
966
+ for(var i=0, l=result.depths.list.length; i<l; i++) {
967
+ depth = result.depths.list[i];
979
968
 
980
- block: function(block) {
981
- var mustache = block.mustache,
982
- program = block.program,
983
- inverse = block.inverse;
969
+ if(depth < 2) { continue; }
970
+ else { this.addDepth(depth - 1); }
971
+ }
984
972
 
985
- if (program) {
986
- program = this.compileProgram(program);
987
- }
973
+ return guid;
974
+ },
988
975
 
989
- if (inverse) {
990
- inverse = this.compileProgram(inverse);
991
- }
976
+ block: function(block) {
977
+ var mustache = block.mustache,
978
+ program = block.program,
979
+ inverse = block.inverse;
992
980
 
993
- var type = this.classifyMustache(mustache);
981
+ if (program) {
982
+ program = this.compileProgram(program);
983
+ }
994
984
 
995
- if (type === "helper") {
996
- this.helperMustache(mustache, program, inverse);
997
- } else if (type === "simple") {
998
- this.simpleMustache(mustache);
985
+ if (inverse) {
986
+ inverse = this.compileProgram(inverse);
987
+ }
999
988
 
1000
- // now that the simple mustache is resolved, we need to
1001
- // evaluate it by executing `blockHelperMissing`
1002
- this.opcode('pushProgram', program);
1003
- this.opcode('pushProgram', inverse);
1004
- this.opcode('emptyHash');
1005
- this.opcode('blockValue');
1006
- } else {
1007
- this.ambiguousMustache(mustache, program, inverse);
1008
-
1009
- // now that the simple mustache is resolved, we need to
1010
- // evaluate it by executing `blockHelperMissing`
1011
- this.opcode('pushProgram', program);
1012
- this.opcode('pushProgram', inverse);
1013
- this.opcode('emptyHash');
1014
- this.opcode('ambiguousBlockValue');
1015
- }
989
+ var type = this.classifyMustache(mustache);
1016
990
 
1017
- this.opcode('append');
1018
- },
991
+ if (type === "helper") {
992
+ this.helperMustache(mustache, program, inverse);
993
+ } else if (type === "simple") {
994
+ this.simpleMustache(mustache);
1019
995
 
1020
- hash: function(hash) {
1021
- var pairs = hash.pairs, pair, val;
996
+ // now that the simple mustache is resolved, we need to
997
+ // evaluate it by executing `blockHelperMissing`
998
+ this.opcode('pushProgram', program);
999
+ this.opcode('pushProgram', inverse);
1000
+ this.opcode('emptyHash');
1001
+ this.opcode('blockValue');
1002
+ } else {
1003
+ this.ambiguousMustache(mustache, program, inverse);
1022
1004
 
1023
- this.opcode('pushHash');
1005
+ // now that the simple mustache is resolved, we need to
1006
+ // evaluate it by executing `blockHelperMissing`
1007
+ this.opcode('pushProgram', program);
1008
+ this.opcode('pushProgram', inverse);
1009
+ this.opcode('emptyHash');
1010
+ this.opcode('ambiguousBlockValue');
1011
+ }
1024
1012
 
1025
- for(var i=0, l=pairs.length; i<l; i++) {
1026
- pair = pairs[i];
1027
- val = pair[1];
1013
+ this.opcode('append');
1014
+ },
1028
1015
 
1029
- if (this.options.stringParams) {
1030
- this.opcode('pushStringParam', val.stringModeValue, val.type);
1031
- } else {
1032
- this.accept(val);
1033
- }
1016
+ hash: function(hash) {
1017
+ var pairs = hash.pairs, pair, val;
1034
1018
 
1035
- this.opcode('assignToHash', pair[0]);
1036
- }
1037
- this.opcode('popHash');
1038
- },
1019
+ this.opcode('pushHash');
1039
1020
 
1040
- partial: function(partial) {
1041
- var partialName = partial.partialName;
1042
- this.usePartial = true;
1021
+ for(var i=0, l=pairs.length; i<l; i++) {
1022
+ pair = pairs[i];
1023
+ val = pair[1];
1043
1024
 
1044
- if(partial.context) {
1045
- this.ID(partial.context);
1025
+ if (this.options.stringParams) {
1026
+ this.opcode('pushStringParam', val.stringModeValue, val.type);
1046
1027
  } else {
1047
- this.opcode('push', 'depth0');
1028
+ this.accept(val);
1048
1029
  }
1049
1030
 
1050
- this.opcode('invokePartial', partialName.name);
1051
- this.opcode('append');
1052
- },
1031
+ this.opcode('assignToHash', pair[0]);
1032
+ }
1033
+ this.opcode('popHash');
1034
+ },
1053
1035
 
1054
- content: function(content) {
1055
- this.opcode('appendContent', content.string);
1056
- },
1036
+ partial: function(partial) {
1037
+ var partialName = partial.partialName;
1038
+ this.usePartial = true;
1057
1039
 
1058
- mustache: function(mustache) {
1059
- var options = this.options;
1060
- var type = this.classifyMustache(mustache);
1040
+ if(partial.context) {
1041
+ this.ID(partial.context);
1042
+ } else {
1043
+ this.opcode('push', 'depth0');
1044
+ }
1061
1045
 
1062
- if (type === "simple") {
1063
- this.simpleMustache(mustache);
1064
- } else if (type === "helper") {
1065
- this.helperMustache(mustache);
1066
- } else {
1067
- this.ambiguousMustache(mustache);
1068
- }
1046
+ this.opcode('invokePartial', partialName.name);
1047
+ this.opcode('append');
1048
+ },
1069
1049
 
1070
- if(mustache.escaped && !options.noEscape) {
1071
- this.opcode('appendEscaped');
1072
- } else {
1073
- this.opcode('append');
1074
- }
1075
- },
1050
+ content: function(content) {
1051
+ this.opcode('appendContent', content.string);
1052
+ },
1076
1053
 
1077
- ambiguousMustache: function(mustache, program, inverse) {
1078
- var id = mustache.id,
1079
- name = id.parts[0],
1080
- isBlock = program != null || inverse != null;
1054
+ mustache: function(mustache) {
1055
+ var options = this.options;
1056
+ var type = this.classifyMustache(mustache);
1081
1057
 
1082
- this.opcode('getContext', id.depth);
1058
+ if (type === "simple") {
1059
+ this.simpleMustache(mustache);
1060
+ } else if (type === "helper") {
1061
+ this.helperMustache(mustache);
1062
+ } else {
1063
+ this.ambiguousMustache(mustache);
1064
+ }
1083
1065
 
1084
- this.opcode('pushProgram', program);
1085
- this.opcode('pushProgram', inverse);
1066
+ if(mustache.escaped && !options.noEscape) {
1067
+ this.opcode('appendEscaped');
1068
+ } else {
1069
+ this.opcode('append');
1070
+ }
1071
+ },
1086
1072
 
1087
- this.opcode('invokeAmbiguous', name, isBlock);
1088
- },
1073
+ ambiguousMustache: function(mustache, program, inverse) {
1074
+ var id = mustache.id,
1075
+ name = id.parts[0],
1076
+ isBlock = program != null || inverse != null;
1089
1077
 
1090
- simpleMustache: function(mustache) {
1091
- var id = mustache.id;
1078
+ this.opcode('getContext', id.depth);
1092
1079
 
1093
- if (id.type === 'DATA') {
1094
- this.DATA(id);
1095
- } else if (id.parts.length) {
1096
- this.ID(id);
1097
- } else {
1098
- // Simplified ID for `this`
1099
- this.addDepth(id.depth);
1100
- this.opcode('getContext', id.depth);
1101
- this.opcode('pushContext');
1102
- }
1103
-
1104
- this.opcode('resolvePossibleLambda');
1105
- },
1080
+ this.opcode('pushProgram', program);
1081
+ this.opcode('pushProgram', inverse);
1106
1082
 
1107
- helperMustache: function(mustache, program, inverse) {
1108
- var params = this.setupFullMustacheParams(mustache, program, inverse),
1109
- name = mustache.id.parts[0];
1083
+ this.opcode('invokeAmbiguous', name, isBlock);
1084
+ },
1110
1085
 
1111
- if (this.options.knownHelpers[name]) {
1112
- this.opcode('invokeKnownHelper', params.length, name);
1113
- } else if (this.knownHelpersOnly) {
1114
- throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
1115
- } else {
1116
- this.opcode('invokeHelper', params.length, name);
1117
- }
1118
- },
1086
+ simpleMustache: function(mustache) {
1087
+ var id = mustache.id;
1119
1088
 
1120
- ID: function(id) {
1089
+ if (id.type === 'DATA') {
1090
+ this.DATA(id);
1091
+ } else if (id.parts.length) {
1092
+ this.ID(id);
1093
+ } else {
1094
+ // Simplified ID for `this`
1121
1095
  this.addDepth(id.depth);
1122
1096
  this.opcode('getContext', id.depth);
1097
+ this.opcode('pushContext');
1098
+ }
1123
1099
 
1124
- var name = id.parts[0];
1125
- if (!name) {
1126
- this.opcode('pushContext');
1127
- } else {
1128
- this.opcode('lookupOnContext', id.parts[0]);
1129
- }
1100
+ this.opcode('resolvePossibleLambda');
1101
+ },
1130
1102
 
1131
- for(var i=1, l=id.parts.length; i<l; i++) {
1132
- this.opcode('lookup', id.parts[i]);
1133
- }
1134
- },
1103
+ helperMustache: function(mustache, program, inverse) {
1104
+ var params = this.setupFullMustacheParams(mustache, program, inverse),
1105
+ name = mustache.id.parts[0];
1135
1106
 
1136
- DATA: function(data) {
1137
- this.options.data = true;
1138
- this.opcode('lookupData', data.id);
1139
- },
1140
-
1141
- STRING: function(string) {
1142
- this.opcode('pushString', string.string);
1143
- },
1107
+ if (this.options.knownHelpers[name]) {
1108
+ this.opcode('invokeKnownHelper', params.length, name);
1109
+ } else if (this.knownHelpersOnly) {
1110
+ throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
1111
+ } else {
1112
+ this.opcode('invokeHelper', params.length, name);
1113
+ }
1114
+ },
1144
1115
 
1145
- INTEGER: function(integer) {
1146
- this.opcode('pushLiteral', integer.integer);
1147
- },
1116
+ ID: function(id) {
1117
+ this.addDepth(id.depth);
1118
+ this.opcode('getContext', id.depth);
1148
1119
 
1149
- BOOLEAN: function(bool) {
1150
- this.opcode('pushLiteral', bool.bool);
1151
- },
1120
+ var name = id.parts[0];
1121
+ if (!name) {
1122
+ this.opcode('pushContext');
1123
+ } else {
1124
+ this.opcode('lookupOnContext', id.parts[0]);
1125
+ }
1152
1126
 
1153
- comment: function() {},
1127
+ for(var i=1, l=id.parts.length; i<l; i++) {
1128
+ this.opcode('lookup', id.parts[i]);
1129
+ }
1130
+ },
1154
1131
 
1155
- // HELPERS
1156
- opcode: function(name) {
1157
- this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
1158
- },
1132
+ DATA: function(data) {
1133
+ this.options.data = true;
1134
+ this.opcode('lookupData', data.id);
1135
+ },
1159
1136
 
1160
- declare: function(name, value) {
1161
- this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
1162
- },
1137
+ STRING: function(string) {
1138
+ this.opcode('pushString', string.string);
1139
+ },
1163
1140
 
1164
- addDepth: function(depth) {
1165
- if(isNaN(depth)) { throw new Error("EWOT"); }
1166
- if(depth === 0) { return; }
1141
+ INTEGER: function(integer) {
1142
+ this.opcode('pushLiteral', integer.integer);
1143
+ },
1167
1144
 
1168
- if(!this.depths[depth]) {
1169
- this.depths[depth] = true;
1170
- this.depths.list.push(depth);
1171
- }
1172
- },
1145
+ BOOLEAN: function(bool) {
1146
+ this.opcode('pushLiteral', bool.bool);
1147
+ },
1173
1148
 
1174
- classifyMustache: function(mustache) {
1175
- var isHelper = mustache.isHelper;
1176
- var isEligible = mustache.eligibleHelper;
1177
- var options = this.options;
1149
+ comment: function() {},
1178
1150
 
1179
- // if ambiguous, we can possibly resolve the ambiguity now
1180
- if (isEligible && !isHelper) {
1181
- var name = mustache.id.parts[0];
1151
+ // HELPERS
1152
+ opcode: function(name) {
1153
+ this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
1154
+ },
1182
1155
 
1183
- if (options.knownHelpers[name]) {
1184
- isHelper = true;
1185
- } else if (options.knownHelpersOnly) {
1186
- isEligible = false;
1187
- }
1188
- }
1156
+ declare: function(name, value) {
1157
+ this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
1158
+ },
1189
1159
 
1190
- if (isHelper) { return "helper"; }
1191
- else if (isEligible) { return "ambiguous"; }
1192
- else { return "simple"; }
1193
- },
1160
+ addDepth: function(depth) {
1161
+ if(isNaN(depth)) { throw new Error("EWOT"); }
1162
+ if(depth === 0) { return; }
1194
1163
 
1195
- pushParams: function(params) {
1196
- var i = params.length, param;
1164
+ if(!this.depths[depth]) {
1165
+ this.depths[depth] = true;
1166
+ this.depths.list.push(depth);
1167
+ }
1168
+ },
1197
1169
 
1198
- while(i--) {
1199
- param = params[i];
1170
+ classifyMustache: function(mustache) {
1171
+ var isHelper = mustache.isHelper;
1172
+ var isEligible = mustache.eligibleHelper;
1173
+ var options = this.options;
1200
1174
 
1201
- if(this.options.stringParams) {
1202
- if(param.depth) {
1203
- this.addDepth(param.depth);
1204
- }
1175
+ // if ambiguous, we can possibly resolve the ambiguity now
1176
+ if (isEligible && !isHelper) {
1177
+ var name = mustache.id.parts[0];
1205
1178
 
1206
- this.opcode('getContext', param.depth || 0);
1207
- this.opcode('pushStringParam', param.stringModeValue, param.type);
1208
- } else {
1209
- this[param.type](param);
1210
- }
1179
+ if (options.knownHelpers[name]) {
1180
+ isHelper = true;
1181
+ } else if (options.knownHelpersOnly) {
1182
+ isEligible = false;
1211
1183
  }
1212
- },
1213
-
1214
- setupMustacheParams: function(mustache) {
1215
- var params = mustache.params;
1216
- this.pushParams(params);
1184
+ }
1217
1185
 
1218
- if(mustache.hash) {
1219
- this.hash(mustache.hash);
1220
- } else {
1221
- this.opcode('emptyHash');
1222
- }
1186
+ if (isHelper) { return "helper"; }
1187
+ else if (isEligible) { return "ambiguous"; }
1188
+ else { return "simple"; }
1189
+ },
1223
1190
 
1224
- return params;
1225
- },
1191
+ pushParams: function(params) {
1192
+ var i = params.length, param;
1226
1193
 
1227
- // this will replace setupMustacheParams when we're done
1228
- setupFullMustacheParams: function(mustache, program, inverse) {
1229
- var params = mustache.params;
1230
- this.pushParams(params);
1194
+ while(i--) {
1195
+ param = params[i];
1231
1196
 
1232
- this.opcode('pushProgram', program);
1233
- this.opcode('pushProgram', inverse);
1197
+ if(this.options.stringParams) {
1198
+ if(param.depth) {
1199
+ this.addDepth(param.depth);
1200
+ }
1234
1201
 
1235
- if(mustache.hash) {
1236
- this.hash(mustache.hash);
1202
+ this.opcode('getContext', param.depth || 0);
1203
+ this.opcode('pushStringParam', param.stringModeValue, param.type);
1237
1204
  } else {
1238
- this.opcode('emptyHash');
1205
+ this[param.type](param);
1239
1206
  }
1207
+ }
1208
+ },
1209
+
1210
+ setupMustacheParams: function(mustache) {
1211
+ var params = mustache.params;
1212
+ this.pushParams(params);
1240
1213
 
1241
- return params;
1214
+ if(mustache.hash) {
1215
+ this.hash(mustache.hash);
1216
+ } else {
1217
+ this.opcode('emptyHash');
1242
1218
  }
1243
- };
1244
1219
 
1245
- var Literal = function(value) {
1246
- this.value = value;
1247
- };
1220
+ return params;
1221
+ },
1248
1222
 
1249
- JavaScriptCompiler.prototype = {
1250
- // PUBLIC API: You can override these methods in a subclass to provide
1251
- // alternative compiled forms for name lookup and buffering semantics
1252
- nameLookup: function(parent, name /* , type*/) {
1253
- if (/^[0-9]+$/.test(name)) {
1254
- return parent + "[" + name + "]";
1255
- } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1256
- return parent + "." + name;
1257
- }
1258
- else {
1259
- return parent + "['" + name + "']";
1260
- }
1261
- },
1223
+ // this will replace setupMustacheParams when we're done
1224
+ setupFullMustacheParams: function(mustache, program, inverse) {
1225
+ var params = mustache.params;
1226
+ this.pushParams(params);
1262
1227
 
1263
- appendToBuffer: function(string) {
1264
- if (this.environment.isSimple) {
1265
- return "return " + string + ";";
1266
- } else {
1267
- return {
1268
- appendToBuffer: true,
1269
- content: string,
1270
- toString: function() { return "buffer += " + string + ";"; }
1271
- };
1272
- }
1273
- },
1228
+ this.opcode('pushProgram', program);
1229
+ this.opcode('pushProgram', inverse);
1274
1230
 
1275
- initializeBuffer: function() {
1276
- return this.quotedString("");
1277
- },
1231
+ if(mustache.hash) {
1232
+ this.hash(mustache.hash);
1233
+ } else {
1234
+ this.opcode('emptyHash');
1235
+ }
1278
1236
 
1279
- namespace: "Handlebars",
1280
- // END PUBLIC API
1237
+ return params;
1238
+ }
1239
+ };
1281
1240
 
1282
- compile: function(environment, options, context, asObject) {
1283
- this.environment = environment;
1284
- this.options = options || {};
1241
+ var Literal = function(value) {
1242
+ this.value = value;
1243
+ };
1285
1244
 
1286
- Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
1245
+ JavaScriptCompiler.prototype = {
1246
+ // PUBLIC API: You can override these methods in a subclass to provide
1247
+ // alternative compiled forms for name lookup and buffering semantics
1248
+ nameLookup: function(parent, name /* , type*/) {
1249
+ if (/^[0-9]+$/.test(name)) {
1250
+ return parent + "[" + name + "]";
1251
+ } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1252
+ return parent + "." + name;
1253
+ }
1254
+ else {
1255
+ return parent + "['" + name + "']";
1256
+ }
1257
+ },
1287
1258
 
1288
- this.name = this.environment.name;
1289
- this.isChild = !!context;
1290
- this.context = context || {
1291
- programs: [],
1292
- environments: [],
1293
- aliases: { }
1259
+ appendToBuffer: function(string) {
1260
+ if (this.environment.isSimple) {
1261
+ return "return " + string + ";";
1262
+ } else {
1263
+ return {
1264
+ appendToBuffer: true,
1265
+ content: string,
1266
+ toString: function() { return "buffer += " + string + ";"; }
1294
1267
  };
1268
+ }
1269
+ },
1295
1270
 
1296
- this.preamble();
1271
+ initializeBuffer: function() {
1272
+ return this.quotedString("");
1273
+ },
1297
1274
 
1298
- this.stackSlot = 0;
1299
- this.stackVars = [];
1300
- this.registers = { list: [] };
1301
- this.compileStack = [];
1302
- this.inlineStack = [];
1275
+ namespace: "Handlebars",
1276
+ // END PUBLIC API
1303
1277
 
1304
- this.compileChildren(environment, options);
1278
+ compile: function(environment, options, context, asObject) {
1279
+ this.environment = environment;
1280
+ this.options = options || {};
1305
1281
 
1306
- var opcodes = environment.opcodes, opcode;
1282
+ Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
1307
1283
 
1308
- this.i = 0;
1284
+ this.name = this.environment.name;
1285
+ this.isChild = !!context;
1286
+ this.context = context || {
1287
+ programs: [],
1288
+ environments: [],
1289
+ aliases: { }
1290
+ };
1309
1291
 
1310
- for(l=opcodes.length; this.i<l; this.i++) {
1311
- opcode = opcodes[this.i];
1292
+ this.preamble();
1312
1293
 
1313
- if(opcode.opcode === 'DECLARE') {
1314
- this[opcode.name] = opcode.value;
1315
- } else {
1316
- this[opcode.opcode].apply(this, opcode.args);
1317
- }
1318
- }
1294
+ this.stackSlot = 0;
1295
+ this.stackVars = [];
1296
+ this.registers = { list: [] };
1297
+ this.compileStack = [];
1298
+ this.inlineStack = [];
1319
1299
 
1320
- return this.createFunctionContext(asObject);
1321
- },
1300
+ this.compileChildren(environment, options);
1322
1301
 
1323
- nextOpcode: function() {
1324
- var opcodes = this.environment.opcodes;
1325
- return opcodes[this.i + 1];
1326
- },
1302
+ var opcodes = environment.opcodes, opcode;
1327
1303
 
1328
- eat: function() {
1329
- this.i = this.i + 1;
1330
- },
1304
+ this.i = 0;
1331
1305
 
1332
- preamble: function() {
1333
- var out = [];
1306
+ for(l=opcodes.length; this.i<l; this.i++) {
1307
+ opcode = opcodes[this.i];
1334
1308
 
1335
- if (!this.isChild) {
1336
- var namespace = this.namespace;
1337
- var copies = "helpers = helpers || " + namespace + ".helpers;";
1338
- if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
1339
- if (this.options.data) { copies = copies + " data = data || {};"; }
1340
- out.push(copies);
1309
+ if(opcode.opcode === 'DECLARE') {
1310
+ this[opcode.name] = opcode.value;
1341
1311
  } else {
1342
- out.push('');
1312
+ this[opcode.opcode].apply(this, opcode.args);
1343
1313
  }
1314
+ }
1344
1315
 
1345
- if (!this.environment.isSimple) {
1346
- out.push(", buffer = " + this.initializeBuffer());
1347
- } else {
1348
- out.push("");
1349
- }
1316
+ return this.createFunctionContext(asObject);
1317
+ },
1350
1318
 
1351
- // track the last context pushed into place to allow skipping the
1352
- // getContext opcode when it would be a noop
1353
- this.lastContext = 0;
1354
- this.source = out;
1355
- },
1319
+ nextOpcode: function() {
1320
+ var opcodes = this.environment.opcodes;
1321
+ return opcodes[this.i + 1];
1322
+ },
1356
1323
 
1357
- createFunctionContext: function(asObject) {
1358
- var locals = this.stackVars.concat(this.registers.list);
1324
+ eat: function() {
1325
+ this.i = this.i + 1;
1326
+ },
1359
1327
 
1360
- if(locals.length > 0) {
1361
- this.source[1] = this.source[1] + ", " + locals.join(", ");
1362
- }
1328
+ preamble: function() {
1329
+ var out = [];
1363
1330
 
1364
- // Generate minimizer alias mappings
1365
- if (!this.isChild) {
1366
- for (var alias in this.context.aliases) {
1367
- this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1368
- }
1369
- }
1331
+ if (!this.isChild) {
1332
+ var namespace = this.namespace;
1333
+ var copies = "helpers = helpers || " + namespace + ".helpers;";
1334
+ if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
1335
+ if (this.options.data) { copies = copies + " data = data || {};"; }
1336
+ out.push(copies);
1337
+ } else {
1338
+ out.push('');
1339
+ }
1370
1340
 
1371
- if (this.source[1]) {
1372
- this.source[1] = "var " + this.source[1].substring(2) + ";";
1373
- }
1341
+ if (!this.environment.isSimple) {
1342
+ out.push(", buffer = " + this.initializeBuffer());
1343
+ } else {
1344
+ out.push("");
1345
+ }
1374
1346
 
1375
- // Merge children
1376
- if (!this.isChild) {
1377
- this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1378
- }
1347
+ // track the last context pushed into place to allow skipping the
1348
+ // getContext opcode when it would be a noop
1349
+ this.lastContext = 0;
1350
+ this.source = out;
1351
+ },
1379
1352
 
1380
- if (!this.environment.isSimple) {
1381
- this.source.push("return buffer;");
1382
- }
1353
+ createFunctionContext: function(asObject) {
1354
+ var locals = this.stackVars.concat(this.registers.list);
1383
1355
 
1384
- var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1356
+ if(locals.length > 0) {
1357
+ this.source[1] = this.source[1] + ", " + locals.join(", ");
1358
+ }
1385
1359
 
1386
- for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1387
- params.push("depth" + this.environment.depths.list[i]);
1360
+ // Generate minimizer alias mappings
1361
+ if (!this.isChild) {
1362
+ for (var alias in this.context.aliases) {
1363
+ this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1388
1364
  }
1365
+ }
1389
1366
 
1390
- // Perform a second pass over the output to merge content when possible
1391
- var source = this.mergeSource();
1367
+ if (this.source[1]) {
1368
+ this.source[1] = "var " + this.source[1].substring(2) + ";";
1369
+ }
1392
1370
 
1393
- if (!this.isChild) {
1394
- var revision = Handlebars.COMPILER_REVISION,
1395
- versions = Handlebars.REVISION_CHANGES[revision];
1396
- source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
1397
- }
1371
+ // Merge children
1372
+ if (!this.isChild) {
1373
+ this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1374
+ }
1398
1375
 
1399
- if (asObject) {
1400
- params.push(source);
1376
+ if (!this.environment.isSimple) {
1377
+ this.source.push("return buffer;");
1378
+ }
1401
1379
 
1402
- return Function.apply(this, params);
1403
- } else {
1404
- var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
1405
- Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1406
- return functionSource;
1407
- }
1408
- },
1409
- mergeSource: function() {
1410
- // WARN: We are not handling the case where buffer is still populated as the source should
1411
- // not have buffer append operations as their final action.
1412
- var source = '',
1413
- buffer;
1414
- for (var i = 0, len = this.source.length; i < len; i++) {
1415
- var line = this.source[i];
1416
- if (line.appendToBuffer) {
1417
- if (buffer) {
1418
- buffer = buffer + '\n + ' + line.content;
1419
- } else {
1420
- buffer = line.content;
1421
- }
1380
+ var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1381
+
1382
+ for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1383
+ params.push("depth" + this.environment.depths.list[i]);
1384
+ }
1385
+
1386
+ // Perform a second pass over the output to merge content when possible
1387
+ var source = this.mergeSource();
1388
+
1389
+ if (!this.isChild) {
1390
+ var revision = Handlebars.COMPILER_REVISION,
1391
+ versions = Handlebars.REVISION_CHANGES[revision];
1392
+ source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
1393
+ }
1394
+
1395
+ if (asObject) {
1396
+ params.push(source);
1397
+
1398
+ return Function.apply(this, params);
1399
+ } else {
1400
+ var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
1401
+ Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1402
+ return functionSource;
1403
+ }
1404
+ },
1405
+ mergeSource: function() {
1406
+ // WARN: We are not handling the case where buffer is still populated as the source should
1407
+ // not have buffer append operations as their final action.
1408
+ var source = '',
1409
+ buffer;
1410
+ for (var i = 0, len = this.source.length; i < len; i++) {
1411
+ var line = this.source[i];
1412
+ if (line.appendToBuffer) {
1413
+ if (buffer) {
1414
+ buffer = buffer + '\n + ' + line.content;
1422
1415
  } else {
1423
- if (buffer) {
1424
- source += 'buffer += ' + buffer + ';\n ';
1425
- buffer = undefined;
1426
- }
1427
- source += line + '\n ';
1416
+ buffer = line.content;
1428
1417
  }
1418
+ } else {
1419
+ if (buffer) {
1420
+ source += 'buffer += ' + buffer + ';\n ';
1421
+ buffer = undefined;
1422
+ }
1423
+ source += line + '\n ';
1429
1424
  }
1430
- return source;
1431
- },
1432
-
1433
- // [blockValue]
1434
- //
1435
- // On stack, before: hash, inverse, program, value
1436
- // On stack, after: return value of blockHelperMissing
1437
- //
1438
- // The purpose of this opcode is to take a block of the form
1439
- // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
1440
- // replace it on the stack with the result of properly
1441
- // invoking blockHelperMissing.
1442
- blockValue: function() {
1443
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1444
-
1445
- var params = ["depth0"];
1446
- this.setupParams(0, params);
1447
-
1448
- this.replaceStack(function(current) {
1449
- params.splice(1, 0, current);
1450
- return "blockHelperMissing.call(" + params.join(", ") + ")";
1451
- });
1452
- },
1425
+ }
1426
+ return source;
1427
+ },
1453
1428
 
1454
- // [ambiguousBlockValue]
1455
- //
1456
- // On stack, before: hash, inverse, program, value
1457
- // Compiler value, before: lastHelper=value of last found helper, if any
1458
- // On stack, after, if no lastHelper: same as [blockValue]
1459
- // On stack, after, if lastHelper: value
1460
- ambiguousBlockValue: function() {
1461
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1429
+ // [blockValue]
1430
+ //
1431
+ // On stack, before: hash, inverse, program, value
1432
+ // On stack, after: return value of blockHelperMissing
1433
+ //
1434
+ // The purpose of this opcode is to take a block of the form
1435
+ // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
1436
+ // replace it on the stack with the result of properly
1437
+ // invoking blockHelperMissing.
1438
+ blockValue: function() {
1439
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1440
+
1441
+ var params = ["depth0"];
1442
+ this.setupParams(0, params);
1443
+
1444
+ this.replaceStack(function(current) {
1445
+ params.splice(1, 0, current);
1446
+ return "blockHelperMissing.call(" + params.join(", ") + ")";
1447
+ });
1448
+ },
1462
1449
 
1463
- var params = ["depth0"];
1464
- this.setupParams(0, params);
1450
+ // [ambiguousBlockValue]
1451
+ //
1452
+ // On stack, before: hash, inverse, program, value
1453
+ // Compiler value, before: lastHelper=value of last found helper, if any
1454
+ // On stack, after, if no lastHelper: same as [blockValue]
1455
+ // On stack, after, if lastHelper: value
1456
+ ambiguousBlockValue: function() {
1457
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1465
1458
 
1466
- var current = this.topStack();
1467
- params.splice(1, 0, current);
1459
+ var params = ["depth0"];
1460
+ this.setupParams(0, params);
1468
1461
 
1469
- // Use the options value generated from the invocation
1470
- params[params.length-1] = 'options';
1462
+ var current = this.topStack();
1463
+ params.splice(1, 0, current);
1471
1464
 
1472
- this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
1473
- },
1465
+ // Use the options value generated from the invocation
1466
+ params[params.length-1] = 'options';
1474
1467
 
1475
- // [appendContent]
1476
- //
1477
- // On stack, before: ...
1478
- // On stack, after: ...
1479
- //
1480
- // Appends the string value of `content` to the current buffer
1481
- appendContent: function(content) {
1482
- this.source.push(this.appendToBuffer(this.quotedString(content)));
1483
- },
1468
+ this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
1469
+ },
1484
1470
 
1485
- // [append]
1486
- //
1487
- // On stack, before: value, ...
1488
- // On stack, after: ...
1489
- //
1490
- // Coerces `value` to a String and appends it to the current buffer.
1491
- //
1492
- // If `value` is truthy, or 0, it is coerced into a string and appended
1493
- // Otherwise, the empty string is appended
1494
- append: function() {
1495
- // Force anything that is inlined onto the stack so we don't have duplication
1496
- // when we examine local
1497
- this.flushInline();
1498
- var local = this.popStack();
1499
- this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1500
- if (this.environment.isSimple) {
1501
- this.source.push("else { " + this.appendToBuffer("''") + " }");
1502
- }
1503
- },
1471
+ // [appendContent]
1472
+ //
1473
+ // On stack, before: ...
1474
+ // On stack, after: ...
1475
+ //
1476
+ // Appends the string value of `content` to the current buffer
1477
+ appendContent: function(content) {
1478
+ this.source.push(this.appendToBuffer(this.quotedString(content)));
1479
+ },
1504
1480
 
1505
- // [appendEscaped]
1506
- //
1507
- // On stack, before: value, ...
1508
- // On stack, after: ...
1509
- //
1510
- // Escape `value` and append it to the buffer
1511
- appendEscaped: function() {
1512
- this.context.aliases.escapeExpression = 'this.escapeExpression';
1481
+ // [append]
1482
+ //
1483
+ // On stack, before: value, ...
1484
+ // On stack, after: ...
1485
+ //
1486
+ // Coerces `value` to a String and appends it to the current buffer.
1487
+ //
1488
+ // If `value` is truthy, or 0, it is coerced into a string and appended
1489
+ // Otherwise, the empty string is appended
1490
+ append: function() {
1491
+ // Force anything that is inlined onto the stack so we don't have duplication
1492
+ // when we examine local
1493
+ this.flushInline();
1494
+ var local = this.popStack();
1495
+ this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1496
+ if (this.environment.isSimple) {
1497
+ this.source.push("else { " + this.appendToBuffer("''") + " }");
1498
+ }
1499
+ },
1513
1500
 
1514
- this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
1515
- },
1501
+ // [appendEscaped]
1502
+ //
1503
+ // On stack, before: value, ...
1504
+ // On stack, after: ...
1505
+ //
1506
+ // Escape `value` and append it to the buffer
1507
+ appendEscaped: function() {
1508
+ this.context.aliases.escapeExpression = 'this.escapeExpression';
1516
1509
 
1517
- // [getContext]
1518
- //
1519
- // On stack, before: ...
1520
- // On stack, after: ...
1521
- // Compiler value, after: lastContext=depth
1522
- //
1523
- // Set the value of the `lastContext` compiler value to the depth
1524
- getContext: function(depth) {
1525
- if(this.lastContext !== depth) {
1526
- this.lastContext = depth;
1527
- }
1528
- },
1510
+ this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
1511
+ },
1529
1512
 
1530
- // [lookupOnContext]
1531
- //
1532
- // On stack, before: ...
1533
- // On stack, after: currentContext[name], ...
1534
- //
1535
- // Looks up the value of `name` on the current context and pushes
1536
- // it onto the stack.
1537
- lookupOnContext: function(name) {
1538
- this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
1539
- },
1513
+ // [getContext]
1514
+ //
1515
+ // On stack, before: ...
1516
+ // On stack, after: ...
1517
+ // Compiler value, after: lastContext=depth
1518
+ //
1519
+ // Set the value of the `lastContext` compiler value to the depth
1520
+ getContext: function(depth) {
1521
+ if(this.lastContext !== depth) {
1522
+ this.lastContext = depth;
1523
+ }
1524
+ },
1540
1525
 
1541
- // [pushContext]
1542
- //
1543
- // On stack, before: ...
1544
- // On stack, after: currentContext, ...
1545
- //
1546
- // Pushes the value of the current context onto the stack.
1547
- pushContext: function() {
1548
- this.pushStackLiteral('depth' + this.lastContext);
1549
- },
1526
+ // [lookupOnContext]
1527
+ //
1528
+ // On stack, before: ...
1529
+ // On stack, after: currentContext[name], ...
1530
+ //
1531
+ // Looks up the value of `name` on the current context and pushes
1532
+ // it onto the stack.
1533
+ lookupOnContext: function(name) {
1534
+ this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
1535
+ },
1550
1536
 
1551
- // [resolvePossibleLambda]
1552
- //
1553
- // On stack, before: value, ...
1554
- // On stack, after: resolved value, ...
1555
- //
1556
- // If the `value` is a lambda, replace it on the stack by
1557
- // the return value of the lambda
1558
- resolvePossibleLambda: function() {
1559
- this.context.aliases.functionType = '"function"';
1560
-
1561
- this.replaceStack(function(current) {
1562
- return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
1563
- });
1564
- },
1537
+ // [pushContext]
1538
+ //
1539
+ // On stack, before: ...
1540
+ // On stack, after: currentContext, ...
1541
+ //
1542
+ // Pushes the value of the current context onto the stack.
1543
+ pushContext: function() {
1544
+ this.pushStackLiteral('depth' + this.lastContext);
1545
+ },
1565
1546
 
1566
- // [lookup]
1567
- //
1568
- // On stack, before: value, ...
1569
- // On stack, after: value[name], ...
1570
- //
1571
- // Replace the value on the stack with the result of looking
1572
- // up `name` on `value`
1573
- lookup: function(name) {
1574
- this.replaceStack(function(current) {
1575
- return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
1576
- });
1577
- },
1547
+ // [resolvePossibleLambda]
1548
+ //
1549
+ // On stack, before: value, ...
1550
+ // On stack, after: resolved value, ...
1551
+ //
1552
+ // If the `value` is a lambda, replace it on the stack by
1553
+ // the return value of the lambda
1554
+ resolvePossibleLambda: function() {
1555
+ this.context.aliases.functionType = '"function"';
1556
+
1557
+ this.replaceStack(function(current) {
1558
+ return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
1559
+ });
1560
+ },
1578
1561
 
1579
- // [lookupData]
1580
- //
1581
- // On stack, before: ...
1582
- // On stack, after: data[id], ...
1583
- //
1584
- // Push the result of looking up `id` on the current data
1585
- lookupData: function(id) {
1586
- this.push(this.nameLookup('data', id, 'data'));
1587
- },
1562
+ // [lookup]
1563
+ //
1564
+ // On stack, before: value, ...
1565
+ // On stack, after: value[name], ...
1566
+ //
1567
+ // Replace the value on the stack with the result of looking
1568
+ // up `name` on `value`
1569
+ lookup: function(name) {
1570
+ this.replaceStack(function(current) {
1571
+ return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
1572
+ });
1573
+ },
1588
1574
 
1589
- // [pushStringParam]
1590
- //
1591
- // On stack, before: ...
1592
- // On stack, after: string, currentContext, ...
1593
- //
1594
- // This opcode is designed for use in string mode, which
1595
- // provides the string value of a parameter along with its
1596
- // depth rather than resolving it immediately.
1597
- pushStringParam: function(string, type) {
1598
- this.pushStackLiteral('depth' + this.lastContext);
1599
-
1600
- this.pushString(type);
1601
-
1602
- if (typeof string === 'string') {
1603
- this.pushString(string);
1604
- } else {
1605
- this.pushStackLiteral(string);
1606
- }
1607
- },
1575
+ // [lookupData]
1576
+ //
1577
+ // On stack, before: ...
1578
+ // On stack, after: data[id], ...
1579
+ //
1580
+ // Push the result of looking up `id` on the current data
1581
+ lookupData: function(id) {
1582
+ this.push(this.nameLookup('data', id, 'data'));
1583
+ },
1608
1584
 
1609
- emptyHash: function() {
1610
- this.pushStackLiteral('{}');
1585
+ // [pushStringParam]
1586
+ //
1587
+ // On stack, before: ...
1588
+ // On stack, after: string, currentContext, ...
1589
+ //
1590
+ // This opcode is designed for use in string mode, which
1591
+ // provides the string value of a parameter along with its
1592
+ // depth rather than resolving it immediately.
1593
+ pushStringParam: function(string, type) {
1594
+ this.pushStackLiteral('depth' + this.lastContext);
1595
+
1596
+ this.pushString(type);
1597
+
1598
+ if (typeof string === 'string') {
1599
+ this.pushString(string);
1600
+ } else {
1601
+ this.pushStackLiteral(string);
1602
+ }
1603
+ },
1611
1604
 
1612
- if (this.options.stringParams) {
1613
- this.register('hashTypes', '{}');
1614
- }
1615
- },
1616
- pushHash: function() {
1617
- this.hash = {values: [], types: []};
1618
- },
1619
- popHash: function() {
1620
- var hash = this.hash;
1621
- this.hash = undefined;
1605
+ emptyHash: function() {
1606
+ this.pushStackLiteral('{}');
1622
1607
 
1623
- if (this.options.stringParams) {
1624
- this.register('hashTypes', '{' + hash.types.join(',') + '}');
1625
- }
1626
- this.push('{\n ' + hash.values.join(',\n ') + '\n }');
1627
- },
1608
+ if (this.options.stringParams) {
1609
+ this.register('hashTypes', '{}');
1610
+ }
1611
+ },
1612
+ pushHash: function() {
1613
+ this.hash = {values: [], types: []};
1614
+ },
1615
+ popHash: function() {
1616
+ var hash = this.hash;
1617
+ this.hash = undefined;
1628
1618
 
1629
- // [pushString]
1630
- //
1631
- // On stack, before: ...
1632
- // On stack, after: quotedString(string), ...
1633
- //
1634
- // Push a quoted version of `string` onto the stack
1635
- pushString: function(string) {
1636
- this.pushStackLiteral(this.quotedString(string));
1637
- },
1619
+ if (this.options.stringParams) {
1620
+ this.register('hashTypes', '{' + hash.types.join(',') + '}');
1621
+ }
1622
+ this.push('{\n ' + hash.values.join(',\n ') + '\n }');
1623
+ },
1638
1624
 
1639
- // [push]
1640
- //
1641
- // On stack, before: ...
1642
- // On stack, after: expr, ...
1643
- //
1644
- // Push an expression onto the stack
1645
- push: function(expr) {
1646
- this.inlineStack.push(expr);
1647
- return expr;
1648
- },
1625
+ // [pushString]
1626
+ //
1627
+ // On stack, before: ...
1628
+ // On stack, after: quotedString(string), ...
1629
+ //
1630
+ // Push a quoted version of `string` onto the stack
1631
+ pushString: function(string) {
1632
+ this.pushStackLiteral(this.quotedString(string));
1633
+ },
1649
1634
 
1650
- // [pushLiteral]
1651
- //
1652
- // On stack, before: ...
1653
- // On stack, after: value, ...
1654
- //
1655
- // Pushes a value onto the stack. This operation prevents
1656
- // the compiler from creating a temporary variable to hold
1657
- // it.
1658
- pushLiteral: function(value) {
1659
- this.pushStackLiteral(value);
1660
- },
1635
+ // [push]
1636
+ //
1637
+ // On stack, before: ...
1638
+ // On stack, after: expr, ...
1639
+ //
1640
+ // Push an expression onto the stack
1641
+ push: function(expr) {
1642
+ this.inlineStack.push(expr);
1643
+ return expr;
1644
+ },
1661
1645
 
1662
- // [pushProgram]
1663
- //
1664
- // On stack, before: ...
1665
- // On stack, after: program(guid), ...
1666
- //
1667
- // Push a program expression onto the stack. This takes
1668
- // a compile-time guid and converts it into a runtime-accessible
1669
- // expression.
1670
- pushProgram: function(guid) {
1671
- if (guid != null) {
1672
- this.pushStackLiteral(this.programExpression(guid));
1673
- } else {
1674
- this.pushStackLiteral(null);
1675
- }
1676
- },
1646
+ // [pushLiteral]
1647
+ //
1648
+ // On stack, before: ...
1649
+ // On stack, after: value, ...
1650
+ //
1651
+ // Pushes a value onto the stack. This operation prevents
1652
+ // the compiler from creating a temporary variable to hold
1653
+ // it.
1654
+ pushLiteral: function(value) {
1655
+ this.pushStackLiteral(value);
1656
+ },
1677
1657
 
1678
- // [invokeHelper]
1679
- //
1680
- // On stack, before: hash, inverse, program, params..., ...
1681
- // On stack, after: result of helper invocation
1682
- //
1683
- // Pops off the helper's parameters, invokes the helper,
1684
- // and pushes the helper's return value onto the stack.
1685
- //
1686
- // If the helper is not found, `helperMissing` is called.
1687
- invokeHelper: function(paramSize, name) {
1688
- this.context.aliases.helperMissing = 'helpers.helperMissing';
1689
-
1690
- var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
1691
-
1692
- this.push(helper.name);
1693
- this.replaceStack(function(name) {
1694
- return name + ' ? ' + name + '.call(' +
1695
- helper.callParams + ") " + ": helperMissing.call(" +
1696
- helper.helperMissingParams + ")";
1697
- });
1698
- },
1658
+ // [pushProgram]
1659
+ //
1660
+ // On stack, before: ...
1661
+ // On stack, after: program(guid), ...
1662
+ //
1663
+ // Push a program expression onto the stack. This takes
1664
+ // a compile-time guid and converts it into a runtime-accessible
1665
+ // expression.
1666
+ pushProgram: function(guid) {
1667
+ if (guid != null) {
1668
+ this.pushStackLiteral(this.programExpression(guid));
1669
+ } else {
1670
+ this.pushStackLiteral(null);
1671
+ }
1672
+ },
1699
1673
 
1700
- // [invokeKnownHelper]
1701
- //
1702
- // On stack, before: hash, inverse, program, params..., ...
1703
- // On stack, after: result of helper invocation
1704
- //
1705
- // This operation is used when the helper is known to exist,
1706
- // so a `helperMissing` fallback is not required.
1707
- invokeKnownHelper: function(paramSize, name) {
1708
- var helper = this.setupHelper(paramSize, name);
1709
- this.push(helper.name + ".call(" + helper.callParams + ")");
1710
- },
1674
+ // [invokeHelper]
1675
+ //
1676
+ // On stack, before: hash, inverse, program, params..., ...
1677
+ // On stack, after: result of helper invocation
1678
+ //
1679
+ // Pops off the helper's parameters, invokes the helper,
1680
+ // and pushes the helper's return value onto the stack.
1681
+ //
1682
+ // If the helper is not found, `helperMissing` is called.
1683
+ invokeHelper: function(paramSize, name) {
1684
+ this.context.aliases.helperMissing = 'helpers.helperMissing';
1685
+
1686
+ var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
1687
+
1688
+ this.push(helper.name);
1689
+ this.replaceStack(function(name) {
1690
+ return name + ' ? ' + name + '.call(' +
1691
+ helper.callParams + ") " + ": helperMissing.call(" +
1692
+ helper.helperMissingParams + ")";
1693
+ });
1694
+ },
1711
1695
 
1712
- // [invokeAmbiguous]
1713
- //
1714
- // On stack, before: hash, inverse, program, params..., ...
1715
- // On stack, after: result of disambiguation
1716
- //
1717
- // This operation is used when an expression like `{{foo}}`
1718
- // is provided, but we don't know at compile-time whether it
1719
- // is a helper or a path.
1720
- //
1721
- // This operation emits more code than the other options,
1722
- // and can be avoided by passing the `knownHelpers` and
1723
- // `knownHelpersOnly` flags at compile-time.
1724
- invokeAmbiguous: function(name, helperCall) {
1725
- this.context.aliases.functionType = '"function"';
1726
-
1727
- this.pushStackLiteral('{}'); // Hash value
1728
- var helper = this.setupHelper(0, name, helperCall);
1729
-
1730
- var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
1731
-
1732
- var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1733
- var nextStack = this.nextStack();
1734
-
1735
- this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
1736
- this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }');
1737
- },
1696
+ // [invokeKnownHelper]
1697
+ //
1698
+ // On stack, before: hash, inverse, program, params..., ...
1699
+ // On stack, after: result of helper invocation
1700
+ //
1701
+ // This operation is used when the helper is known to exist,
1702
+ // so a `helperMissing` fallback is not required.
1703
+ invokeKnownHelper: function(paramSize, name) {
1704
+ var helper = this.setupHelper(paramSize, name);
1705
+ this.push(helper.name + ".call(" + helper.callParams + ")");
1706
+ },
1738
1707
 
1739
- // [invokePartial]
1740
- //
1741
- // On stack, before: context, ...
1742
- // On stack after: result of partial invocation
1743
- //
1744
- // This operation pops off a context, invokes a partial with that context,
1745
- // and pushes the result of the invocation back.
1746
- invokePartial: function(name) {
1747
- var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
1748
-
1749
- if (this.options.data) {
1750
- params.push("data");
1751
- }
1708
+ // [invokeAmbiguous]
1709
+ //
1710
+ // On stack, before: hash, inverse, program, params..., ...
1711
+ // On stack, after: result of disambiguation
1712
+ //
1713
+ // This operation is used when an expression like `{{foo}}`
1714
+ // is provided, but we don't know at compile-time whether it
1715
+ // is a helper or a path.
1716
+ //
1717
+ // This operation emits more code than the other options,
1718
+ // and can be avoided by passing the `knownHelpers` and
1719
+ // `knownHelpersOnly` flags at compile-time.
1720
+ invokeAmbiguous: function(name, helperCall) {
1721
+ this.context.aliases.functionType = '"function"';
1722
+
1723
+ this.pushStackLiteral('{}'); // Hash value
1724
+ var helper = this.setupHelper(0, name, helperCall);
1725
+
1726
+ var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
1727
+
1728
+ var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1729
+ var nextStack = this.nextStack();
1730
+
1731
+ this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
1732
+ this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }');
1733
+ },
1752
1734
 
1753
- this.context.aliases.self = "this";
1754
- this.push("self.invokePartial(" + params.join(", ") + ")");
1755
- },
1735
+ // [invokePartial]
1736
+ //
1737
+ // On stack, before: context, ...
1738
+ // On stack after: result of partial invocation
1739
+ //
1740
+ // This operation pops off a context, invokes a partial with that context,
1741
+ // and pushes the result of the invocation back.
1742
+ invokePartial: function(name) {
1743
+ var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
1744
+
1745
+ if (this.options.data) {
1746
+ params.push("data");
1747
+ }
1756
1748
 
1757
- // [assignToHash]
1758
- //
1759
- // On stack, before: value, hash, ...
1760
- // On stack, after: hash, ...
1761
- //
1762
- // Pops a value and hash off the stack, assigns `hash[key] = value`
1763
- // and pushes the hash back onto the stack.
1764
- assignToHash: function(key) {
1765
- var value = this.popStack(),
1766
- type;
1749
+ this.context.aliases.self = "this";
1750
+ this.push("self.invokePartial(" + params.join(", ") + ")");
1751
+ },
1767
1752
 
1768
- if (this.options.stringParams) {
1769
- type = this.popStack();
1770
- this.popStack();
1771
- }
1753
+ // [assignToHash]
1754
+ //
1755
+ // On stack, before: value, hash, ...
1756
+ // On stack, after: hash, ...
1757
+ //
1758
+ // Pops a value and hash off the stack, assigns `hash[key] = value`
1759
+ // and pushes the hash back onto the stack.
1760
+ assignToHash: function(key) {
1761
+ var value = this.popStack(),
1762
+ type;
1763
+
1764
+ if (this.options.stringParams) {
1765
+ type = this.popStack();
1766
+ this.popStack();
1767
+ }
1772
1768
 
1773
- var hash = this.hash;
1774
- if (type) {
1775
- hash.types.push("'" + key + "': " + type);
1776
- }
1777
- hash.values.push("'" + key + "': (" + value + ")");
1778
- },
1769
+ var hash = this.hash;
1770
+ if (type) {
1771
+ hash.types.push("'" + key + "': " + type);
1772
+ }
1773
+ hash.values.push("'" + key + "': (" + value + ")");
1774
+ },
1779
1775
 
1780
- // HELPERS
1776
+ // HELPERS
1781
1777
 
1782
- compiler: JavaScriptCompiler,
1778
+ compiler: JavaScriptCompiler,
1783
1779
 
1784
- compileChildren: function(environment, options) {
1785
- var children = environment.children, child, compiler;
1780
+ compileChildren: function(environment, options) {
1781
+ var children = environment.children, child, compiler;
1786
1782
 
1787
- for(var i=0, l=children.length; i<l; i++) {
1788
- child = children[i];
1789
- compiler = new this.compiler();
1783
+ for(var i=0, l=children.length; i<l; i++) {
1784
+ child = children[i];
1785
+ compiler = new this.compiler();
1790
1786
 
1791
- var index = this.matchExistingProgram(child);
1787
+ var index = this.matchExistingProgram(child);
1792
1788
 
1793
- if (index == null) {
1794
- this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
1795
- index = this.context.programs.length;
1796
- child.index = index;
1797
- child.name = 'program' + index;
1798
- this.context.programs[index] = compiler.compile(child, options, this.context);
1799
- this.context.environments[index] = child;
1800
- } else {
1801
- child.index = index;
1802
- child.name = 'program' + index;
1803
- }
1789
+ if (index == null) {
1790
+ this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
1791
+ index = this.context.programs.length;
1792
+ child.index = index;
1793
+ child.name = 'program' + index;
1794
+ this.context.programs[index] = compiler.compile(child, options, this.context);
1795
+ this.context.environments[index] = child;
1796
+ } else {
1797
+ child.index = index;
1798
+ child.name = 'program' + index;
1804
1799
  }
1805
- },
1806
- matchExistingProgram: function(child) {
1807
- for (var i = 0, len = this.context.environments.length; i < len; i++) {
1808
- var environment = this.context.environments[i];
1809
- if (environment && environment.equals(child)) {
1810
- return i;
1811
- }
1800
+ }
1801
+ },
1802
+ matchExistingProgram: function(child) {
1803
+ for (var i = 0, len = this.context.environments.length; i < len; i++) {
1804
+ var environment = this.context.environments[i];
1805
+ if (environment && environment.equals(child)) {
1806
+ return i;
1812
1807
  }
1813
- },
1814
-
1815
- programExpression: function(guid) {
1816
- this.context.aliases.self = "this";
1808
+ }
1809
+ },
1817
1810
 
1818
- if(guid == null) {
1819
- return "self.noop";
1820
- }
1811
+ programExpression: function(guid) {
1812
+ this.context.aliases.self = "this";
1821
1813
 
1822
- var child = this.environment.children[guid],
1823
- depths = child.depths.list, depth;
1814
+ if(guid == null) {
1815
+ return "self.noop";
1816
+ }
1824
1817
 
1825
- var programParams = [child.index, child.name, "data"];
1818
+ var child = this.environment.children[guid],
1819
+ depths = child.depths.list, depth;
1826
1820
 
1827
- for(var i=0, l = depths.length; i<l; i++) {
1828
- depth = depths[i];
1821
+ var programParams = [child.index, child.name, "data"];
1829
1822
 
1830
- if(depth === 1) { programParams.push("depth0"); }
1831
- else { programParams.push("depth" + (depth - 1)); }
1832
- }
1823
+ for(var i=0, l = depths.length; i<l; i++) {
1824
+ depth = depths[i];
1833
1825
 
1834
- if(depths.length === 0) {
1835
- return "self.program(" + programParams.join(", ") + ")";
1836
- } else {
1837
- programParams.shift();
1838
- return "self.programWithDepth(" + programParams.join(", ") + ")";
1839
- }
1840
- },
1826
+ if(depth === 1) { programParams.push("depth0"); }
1827
+ else { programParams.push("depth" + (depth - 1)); }
1828
+ }
1841
1829
 
1842
- register: function(name, val) {
1843
- this.useRegister(name);
1844
- this.source.push(name + " = " + val + ";");
1845
- },
1830
+ if(depths.length === 0) {
1831
+ return "self.program(" + programParams.join(", ") + ")";
1832
+ } else {
1833
+ programParams.shift();
1834
+ return "self.programWithDepth(" + programParams.join(", ") + ")";
1835
+ }
1836
+ },
1846
1837
 
1847
- useRegister: function(name) {
1848
- if(!this.registers[name]) {
1849
- this.registers[name] = true;
1850
- this.registers.list.push(name);
1851
- }
1852
- },
1838
+ register: function(name, val) {
1839
+ this.useRegister(name);
1840
+ this.source.push(name + " = " + val + ";");
1841
+ },
1853
1842
 
1854
- pushStackLiteral: function(item) {
1855
- return this.push(new Literal(item));
1856
- },
1843
+ useRegister: function(name) {
1844
+ if(!this.registers[name]) {
1845
+ this.registers[name] = true;
1846
+ this.registers.list.push(name);
1847
+ }
1848
+ },
1857
1849
 
1858
- pushStack: function(item) {
1859
- this.flushInline();
1850
+ pushStackLiteral: function(item) {
1851
+ return this.push(new Literal(item));
1852
+ },
1860
1853
 
1861
- var stack = this.incrStack();
1862
- if (item) {
1863
- this.source.push(stack + " = " + item + ";");
1864
- }
1865
- this.compileStack.push(stack);
1866
- return stack;
1867
- },
1854
+ pushStack: function(item) {
1855
+ this.flushInline();
1868
1856
 
1869
- replaceStack: function(callback) {
1870
- var prefix = '',
1871
- inline = this.isInline(),
1872
- stack;
1857
+ var stack = this.incrStack();
1858
+ if (item) {
1859
+ this.source.push(stack + " = " + item + ";");
1860
+ }
1861
+ this.compileStack.push(stack);
1862
+ return stack;
1863
+ },
1873
1864
 
1874
- // If we are currently inline then we want to merge the inline statement into the
1875
- // replacement statement via ','
1876
- if (inline) {
1877
- var top = this.popStack(true);
1865
+ replaceStack: function(callback) {
1866
+ var prefix = '',
1867
+ inline = this.isInline(),
1868
+ stack;
1878
1869
 
1879
- if (top instanceof Literal) {
1880
- // Literals do not need to be inlined
1881
- stack = top.value;
1882
- } else {
1883
- // Get or create the current stack name for use by the inline
1884
- var name = this.stackSlot ? this.topStackName() : this.incrStack();
1870
+ // If we are currently inline then we want to merge the inline statement into the
1871
+ // replacement statement via ','
1872
+ if (inline) {
1873
+ var top = this.popStack(true);
1885
1874
 
1886
- prefix = '(' + this.push(name) + ' = ' + top + '),';
1887
- stack = this.topStack();
1888
- }
1875
+ if (top instanceof Literal) {
1876
+ // Literals do not need to be inlined
1877
+ stack = top.value;
1889
1878
  } else {
1879
+ // Get or create the current stack name for use by the inline
1880
+ var name = this.stackSlot ? this.topStackName() : this.incrStack();
1881
+
1882
+ prefix = '(' + this.push(name) + ' = ' + top + '),';
1890
1883
  stack = this.topStack();
1891
1884
  }
1885
+ } else {
1886
+ stack = this.topStack();
1887
+ }
1892
1888
 
1893
- var item = callback.call(this, stack);
1894
-
1895
- if (inline) {
1896
- if (this.inlineStack.length || this.compileStack.length) {
1897
- this.popStack();
1898
- }
1899
- this.push('(' + prefix + item + ')');
1900
- } else {
1901
- // Prevent modification of the context depth variable. Through replaceStack
1902
- if (!/^stack/.test(stack)) {
1903
- stack = this.nextStack();
1904
- }
1889
+ var item = callback.call(this, stack);
1905
1890
 
1906
- this.source.push(stack + " = (" + prefix + item + ");");
1891
+ if (inline) {
1892
+ if (this.inlineStack.length || this.compileStack.length) {
1893
+ this.popStack();
1907
1894
  }
1908
- return stack;
1909
- },
1910
-
1911
- nextStack: function() {
1912
- return this.pushStack();
1913
- },
1914
-
1915
- incrStack: function() {
1916
- this.stackSlot++;
1917
- if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1918
- return this.topStackName();
1919
- },
1920
- topStackName: function() {
1921
- return "stack" + this.stackSlot;
1922
- },
1923
- flushInline: function() {
1924
- var inlineStack = this.inlineStack;
1925
- if (inlineStack.length) {
1926
- this.inlineStack = [];
1927
- for (var i = 0, len = inlineStack.length; i < len; i++) {
1928
- var entry = inlineStack[i];
1929
- if (entry instanceof Literal) {
1930
- this.compileStack.push(entry);
1931
- } else {
1932
- this.pushStack(entry);
1933
- }
1934
- }
1895
+ this.push('(' + prefix + item + ')');
1896
+ } else {
1897
+ // Prevent modification of the context depth variable. Through replaceStack
1898
+ if (!/^stack/.test(stack)) {
1899
+ stack = this.nextStack();
1935
1900
  }
1936
- },
1937
- isInline: function() {
1938
- return this.inlineStack.length;
1939
- },
1940
1901
 
1941
- popStack: function(wrapped) {
1942
- var inline = this.isInline(),
1943
- item = (inline ? this.inlineStack : this.compileStack).pop();
1902
+ this.source.push(stack + " = (" + prefix + item + ");");
1903
+ }
1904
+ return stack;
1905
+ },
1906
+
1907
+ nextStack: function() {
1908
+ return this.pushStack();
1909
+ },
1944
1910
 
1945
- if (!wrapped && (item instanceof Literal)) {
1946
- return item.value;
1947
- } else {
1948
- if (!inline) {
1949
- this.stackSlot--;
1911
+ incrStack: function() {
1912
+ this.stackSlot++;
1913
+ if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1914
+ return this.topStackName();
1915
+ },
1916
+ topStackName: function() {
1917
+ return "stack" + this.stackSlot;
1918
+ },
1919
+ flushInline: function() {
1920
+ var inlineStack = this.inlineStack;
1921
+ if (inlineStack.length) {
1922
+ this.inlineStack = [];
1923
+ for (var i = 0, len = inlineStack.length; i < len; i++) {
1924
+ var entry = inlineStack[i];
1925
+ if (entry instanceof Literal) {
1926
+ this.compileStack.push(entry);
1927
+ } else {
1928
+ this.pushStack(entry);
1950
1929
  }
1951
- return item;
1952
1930
  }
1953
- },
1931
+ }
1932
+ },
1933
+ isInline: function() {
1934
+ return this.inlineStack.length;
1935
+ },
1954
1936
 
1955
- topStack: function(wrapped) {
1956
- var stack = (this.isInline() ? this.inlineStack : this.compileStack),
1957
- item = stack[stack.length - 1];
1937
+ popStack: function(wrapped) {
1938
+ var inline = this.isInline(),
1939
+ item = (inline ? this.inlineStack : this.compileStack).pop();
1958
1940
 
1959
- if (!wrapped && (item instanceof Literal)) {
1960
- return item.value;
1961
- } else {
1962
- return item;
1941
+ if (!wrapped && (item instanceof Literal)) {
1942
+ return item.value;
1943
+ } else {
1944
+ if (!inline) {
1945
+ this.stackSlot--;
1963
1946
  }
1964
- },
1947
+ return item;
1948
+ }
1949
+ },
1965
1950
 
1966
- quotedString: function(str) {
1967
- return '"' + str
1968
- .replace(/\\/g, '\\\\')
1969
- .replace(/"/g, '\\"')
1970
- .replace(/\n/g, '\\n')
1971
- .replace(/\r/g, '\\r') + '"';
1972
- },
1951
+ topStack: function(wrapped) {
1952
+ var stack = (this.isInline() ? this.inlineStack : this.compileStack),
1953
+ item = stack[stack.length - 1];
1954
+
1955
+ if (!wrapped && (item instanceof Literal)) {
1956
+ return item.value;
1957
+ } else {
1958
+ return item;
1959
+ }
1960
+ },
1973
1961
 
1974
- setupHelper: function(paramSize, name, missingParams) {
1975
- var params = [];
1976
- this.setupParams(paramSize, params, missingParams);
1977
- var foundHelper = this.nameLookup('helpers', name, 'helper');
1962
+ quotedString: function(str) {
1963
+ return '"' + str
1964
+ .replace(/\\/g, '\\\\')
1965
+ .replace(/"/g, '\\"')
1966
+ .replace(/\n/g, '\\n')
1967
+ .replace(/\r/g, '\\r') + '"';
1968
+ },
1978
1969
 
1979
- return {
1980
- params: params,
1981
- name: foundHelper,
1982
- callParams: ["depth0"].concat(params).join(", "),
1983
- helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
1984
- };
1985
- },
1970
+ setupHelper: function(paramSize, name, missingParams) {
1971
+ var params = [];
1972
+ this.setupParams(paramSize, params, missingParams);
1973
+ var foundHelper = this.nameLookup('helpers', name, 'helper');
1986
1974
 
1987
- // the params and contexts arguments are passed in arrays
1988
- // to fill in
1989
- setupParams: function(paramSize, params, useRegister) {
1990
- var options = [], contexts = [], types = [], param, inverse, program;
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
+ };
1981
+ },
1991
1982
 
1992
- options.push("hash:" + this.popStack());
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;
1993
1987
 
1994
- inverse = this.popStack();
1995
- program = this.popStack();
1988
+ options.push("hash:" + this.popStack());
1996
1989
 
1997
- // Avoid setting fn and inverse if neither are set. This allows
1998
- // helpers to do a check for `if (options.fn)`
1999
- if (program || inverse) {
2000
- if (!program) {
2001
- this.context.aliases.self = "this";
2002
- program = "self.noop";
2003
- }
1990
+ inverse = this.popStack();
1991
+ program = this.popStack();
2004
1992
 
2005
- if (!inverse) {
2006
- this.context.aliases.self = "this";
2007
- inverse = "self.noop";
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
2000
 
2010
- options.push("inverse:" + inverse);
2011
- options.push("fn:" + program);
2001
+ if (!inverse) {
2002
+ this.context.aliases.self = "this";
2003
+ inverse = "self.noop";
2012
2004
  }
2013
2005
 
2014
- for(var i=0; i<paramSize; i++) {
2015
- param = this.popStack();
2016
- params.push(param);
2006
+ options.push("inverse:" + inverse);
2007
+ options.push("fn:" + program);
2008
+ }
2017
2009
 
2018
- if(this.options.stringParams) {
2019
- types.push(this.popStack());
2020
- contexts.push(this.popStack());
2021
- }
2022
- }
2010
+ for(var i=0; i<paramSize; i++) {
2011
+ param = this.popStack();
2012
+ params.push(param);
2023
2013
 
2024
- if (this.options.stringParams) {
2025
- options.push("contexts:[" + contexts.join(",") + "]");
2026
- options.push("types:[" + types.join(",") + "]");
2027
- options.push("hashTypes:hashTypes");
2014
+ if(this.options.stringParams) {
2015
+ types.push(this.popStack());
2016
+ contexts.push(this.popStack());
2028
2017
  }
2018
+ }
2029
2019
 
2030
- if(this.options.data) {
2031
- options.push("data:data");
2032
- }
2020
+ if (this.options.stringParams) {
2021
+ options.push("contexts:[" + contexts.join(",") + "]");
2022
+ options.push("types:[" + types.join(",") + "]");
2023
+ options.push("hashTypes:hashTypes");
2024
+ }
2033
2025
 
2034
- options = "{" + options.join(",") + "}";
2035
- if (useRegister) {
2036
- this.register('options', options);
2037
- params.push('options');
2038
- } else {
2039
- params.push(options);
2040
- }
2041
- return params.join(", ");
2026
+ if(this.options.data) {
2027
+ options.push("data:data");
2042
2028
  }
2043
- };
2044
2029
 
2045
- var reservedWords = (
2046
- "break else new var" +
2047
- " case finally return void" +
2048
- " catch for switch while" +
2049
- " continue function this with" +
2050
- " default if throw" +
2051
- " delete in try" +
2052
- " do instanceof typeof" +
2053
- " abstract enum int short" +
2054
- " boolean export interface static" +
2055
- " byte extends long super" +
2056
- " char final native synchronized" +
2057
- " class float package throws" +
2058
- " const goto private transient" +
2059
- " debugger implements protected volatile" +
2060
- " double import public let yield"
2061
- ).split(" ");
2062
-
2063
- var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
2064
-
2065
- for(var i=0, l=reservedWords.length; i<l; i++) {
2066
- compilerWords[reservedWords[i]] = true;
2030
+ options = "{" + options.join(",") + "}";
2031
+ if (useRegister) {
2032
+ this.register('options', options);
2033
+ params.push('options');
2034
+ } else {
2035
+ params.push(options);
2036
+ }
2037
+ return params.join(", ");
2067
2038
  }
2039
+ };
2068
2040
 
2069
- JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
2070
- if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
2071
- return true;
2072
- }
2073
- return false;
2074
- };
2041
+ var reservedWords = (
2042
+ "break else new var" +
2043
+ " case finally return void" +
2044
+ " catch for switch while" +
2045
+ " continue function this with" +
2046
+ " default if throw" +
2047
+ " delete in try" +
2048
+ " do instanceof typeof" +
2049
+ " abstract enum int short" +
2050
+ " boolean export interface static" +
2051
+ " byte extends long super" +
2052
+ " char final native synchronized" +
2053
+ " class float package throws" +
2054
+ " const goto private transient" +
2055
+ " debugger implements protected volatile" +
2056
+ " double import public let yield"
2057
+ ).split(" ");
2058
+
2059
+ var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
2060
+
2061
+ for(var i=0, l=reservedWords.length; i<l; i++) {
2062
+ compilerWords[reservedWords[i]] = true;
2063
+ }
2075
2064
 
2076
- })(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
2065
+ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
2066
+ if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
2067
+ return true;
2068
+ }
2069
+ return false;
2070
+ };
2077
2071
 
2078
2072
  Handlebars.precompile = function(input, options) {
2079
2073
  if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2080
- throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
2074
+ throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
2081
2075
  }
2082
2076
 
2083
2077
  options = options || {};
@@ -2085,8 +2079,8 @@ Handlebars.precompile = function(input, options) {
2085
2079
  options.data = true;
2086
2080
  }
2087
2081
  var ast = Handlebars.parse(input);
2088
- var environment = new Handlebars.Compiler().compile(ast, options);
2089
- return new Handlebars.JavaScriptCompiler().compile(environment, options);
2082
+ var environment = new Compiler().compile(ast, options);
2083
+ return new JavaScriptCompiler().compile(environment, options);
2090
2084
  };
2091
2085
 
2092
2086
  Handlebars.compile = function(input, options) {
@@ -2101,8 +2095,8 @@ Handlebars.compile = function(input, options) {
2101
2095
  var compiled;
2102
2096
  function compile() {
2103
2097
  var ast = Handlebars.parse(input);
2104
- var environment = new Handlebars.Compiler().compile(ast, options);
2105
- var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
2098
+ var environment = new Compiler().compile(ast, options);
2099
+ var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true);
2106
2100
  return Handlebars.template(templateSpec);
2107
2101
  }
2108
2102
 
@@ -2114,8 +2108,10 @@ Handlebars.compile = function(input, options) {
2114
2108
  return compiled.call(this, context, options);
2115
2109
  };
2116
2110
  };
2111
+
2117
2112
  ;
2118
2113
  // lib/handlebars/runtime.js
2114
+
2119
2115
  Handlebars.VM = {
2120
2116
  template: function(templateSpec) {
2121
2117
  // Just add water
@@ -2199,3 +2195,6 @@ Handlebars.VM = {
2199
2195
 
2200
2196
  Handlebars.template = Handlebars.VM.template;
2201
2197
  ;
2198
+ // lib/handlebars/browser-suffix.js
2199
+ })(Handlebars);
2200
+ ;