import Exception from "../exception"; import {isArray} from "../utils"; var slice = [].slice; export function Compiler() {} // the foundHelper register will disambiguate helper lookup from finding a // function in a context. This is necessary for mustache compatibility, which // requires that context functions in blocks are evaluated by blockHelperMissing, // and then proceed as if the resulting value was provided to blockHelperMissing. Compiler.prototype = { compiler: Compiler, equals: function(other) { var len = this.opcodes.length; if (other.opcodes.length !== len) { return false; } for (var i = 0; i < len; i++) { var opcode = this.opcodes[i], otherOpcode = other.opcodes[i]; if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) { return false; } } // We know that length is the same between the two arrays because they are directly tied // to the opcode behavior above. len = this.children.length; for (i = 0; i < len; i++) { if (!this.children[i].equals(other.children[i])) { return false; } } return true; }, guid: 0, compile: function(program, options) { this.opcodes = []; this.children = []; this.depths = {list: []}; this.options = options; this.stringParams = options.stringParams; this.trackIds = options.trackIds; // These changes will propagate to the other compiler components var knownHelpers = this.options.knownHelpers; this.options.knownHelpers = { 'helperMissing': true, 'blockHelperMissing': true, 'each': true, 'if': true, 'unless': true, 'with': true, 'log': true, 'lookup': true }; if (knownHelpers) { for (var name in knownHelpers) { this.options.knownHelpers[name] = knownHelpers[name]; } } return this.accept(program); }, accept: function(node) { return this[node.type](node); }, Program: function(program) { var body = program.body; for(var i=0, l=body.length; i 1) { throw new Exception('Unsupported number of partial arguments: ' + params.length, partial); } this.pushParam(params[0]); } else { this.opcode('getContext', partial, 0); this.opcode('pushContext', partial); } var indent = partial.indent || ''; if (this.options.preventIndent && indent) { this.opcode('appendContent', partial, indent); indent = ''; } this.opcode('invokePartial', partial, partialName, indent); this.opcode('append', partial); }, MustacheStatement: function(mustache) { this.sexpr(mustache.sexpr); if(mustache.escaped && !this.options.noEscape) { this.opcode('appendEscaped', mustache); } else { this.opcode('append', mustache); } }, ContentStatement: function(content) { if (content.value) { this.opcode('appendContent', content, content.value); } }, CommentStatement: function() {}, sexpr: function(sexpr) { var type = this.classifySexpr(sexpr); if (type === "simple") { this.simpleSexpr(sexpr); } else if (type === "helper") { this.helperSexpr(sexpr); } else { this.ambiguousSexpr(sexpr); } }, ambiguousSexpr: function(sexpr, program, inverse) { var id = sexpr.id, name = id.parts[0], isBlock = program != null || inverse != null; this.opcode('getContext', sexpr, id.depth); this.opcode('pushProgram', sexpr, program); this.opcode('pushProgram', sexpr, inverse); this.accept(id); this.opcode('invokeAmbiguous', sexpr, name, isBlock); }, simpleSexpr: function(sexpr) { var id = sexpr.id; if (id.parts.length) { this.accept(id); } else { // Simplified ID for `this` this.addDepth(id.depth); this.opcode('getContext', sexpr, id.depth); this.opcode('pushContext', sexpr); } this.opcode('resolvePossibleLambda', sexpr); }, helperSexpr: function(sexpr, program, inverse) { var params = this.setupFullMustacheParams(sexpr, program, inverse), id = sexpr.id, name = id.parts[0]; if (this.options.knownHelpers[name]) { this.opcode('invokeKnownHelper', sexpr, params.length, name); } else if (this.options.knownHelpersOnly) { throw new Exception("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr); } else { id.falsy = true; this.accept(id); this.opcode('invokeHelper', sexpr, params.length, id.original, id.isSimple); } }, hash: function(hash) { var pairs = hash.pairs, i, l; this.opcode('pushHash', hash); for(i=0, l=pairs.length; i