handlebars-source 1.0.0.rc2 → 1.0.0.rc3

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.
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
+ ;