SwiftJsTemplate (v2)

Revision 2 of this benchmark created by Young on


Description

performance testing compare with handlebar

Preparation HTML

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0-alpha.4/handlebars.js"></script>
<div class="test_text_1">
        <div>{{HelloWorld}}</div>
    </div>
    
    <div class="test_text_2">
        <div>Hello World</div>
    </div>

    <div class="test_text_3">
        {{!-- Hello World --}}
        <div>{{HelloWorld}}</div>
    </div>

    <div class="test_text_4">
        <div>{{a.b.c}}</div>
    </div>

    <div class="test_text_5">
        <div>{{$root.a.b.c}}</div>
    </div>

Setup

/*
    Copyright (c) 2014-6-5 Young Zhang
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
    */
    (function(window) {
      //var RuleCatigory = {
      //    TEXT: "TEXT",
      //    EXPRESSION: "EXPRESSION",
      //}
    
      var _utility = (function() {
        var getContextNames = function(contextIds) {
          var names = "";
          for (var ruleName in RuleContext) {
            if (contextIds & RuleContext[ruleName]) {
              names += " | " + ruleName;
            }
          }
          return names.substring(3);
        }
        return {
          getContextNames: getContextNames
        };
      })();
    
      /*
       *Document
       *  |-COMMENT -> (Document)
       *  |-TEXT -> (Document)
       *  |-BLOCK -> (Document)
       *  |   |-CONDITION -> (Document ||)
       *  |   |   |-FUNCTION
       *  |   |
       *  |   |-BREAK
       *  |
       *  |-FUNCTION -> (COMMENT || TEXT || BLOCK || VARIABLE)
       *  |   |-FUNCTION
       *  |   |-VARIABLE
       *  |   |-TEXT
       *  |
       *  |-VARIABLE -> (COMMENT || TEXT || FUNCTION || VARIABLE)
       *      |-VARIABLE
       *      |-TEXT
       *                                      MOC(Must Have|One Inner Context):(example)
       *DOCUMENT                              10
       *  |-CONSTANT                          00:<div>1</div>
       *  |-EXECUTABLE                        01:{{...}}
       *      |-VARIABLE                      00:dog
       *      |   |-VARIABLE
       *      |   |-CONSTANT
       *      |
       *      |-FUNCTION                      01:abc(...)
       *      |   |-FUNCTION
       *      |   |-VARIABLE
       *      |   |-CONSTANT
       *      |
       *      |-BLOCK                         01:#
       *      |   |-CONDITION                 10:if
       *      |   |   |-FUNCTION
       *      |   |   |-VARIABLE
       *      |   |   |-CONSTANT
       *      |   |
       *      |   |-CONSTANT
       *      |   |-EXECUTABLE
       *      |   |-GOTO                      00:break
       *      |       |-FUNCTION
       *      |       |-VARIABLE
       *      |       |-CONSTANT
       *      |
       *      |-COMMENT                      00:!It's Comments
       *
       **/
      var SwiftContextType = {
        //DOCUMENT: "DOCUMENT",
        //CONSTANT: "CONSTANT",
        //EXECUTABLE: "EXCUTABLE",
        //VARIABLE: "VARIABLE",
        //FUNCTION: "FUNCTION",
        //BLOCK: "BLOCK",
        //CONDITION: "CONDITION",
        //GOTO: "GOTO",
        //COMMENT: "COMMENT"
        DOCUMENT: 1 << 0, //1
        CONSTANT: 1 << 1, //2
        EXECUTABLE: 1 << 2, //4
        VARIABLE: 1 << 3, //8
        FUNCTION: 1 << 4, //16
        BLOCK: 1 << 5, //32
        CONDITION: 1 << 6, //64
        ENDBLOCK: 1 << 7, //128
        GOTO: 1 << 8, //256
        COMMENT: 1 << 9 //512
      }
      var SwiftContextTypeName = {
        //DOCUMENT: "DOCUMENT",
        //CONSTANT: "CONSTANT",
        //EXECUTABLE: "EXCUTABLE",
        //VARIABLE: "VARIABLE",
        //FUNCTION: "FUNCTION",
        //BLOCK: "BLOCK",
        //CONDITION: "CONDITION",
        //GOTO: "GOTO",
        //COMMENT: "COMMENT"
        1: "DOCUMENT", //1
        2: "CONSTANT", //2
        4: "EXECUTABLE", //4
        8: "VARIABLE", //8
        16: "FUNCTION", //16
        32: "BLOCK", //32
        64: "CONDITION", //64
        128: "ENDBLOCK", //128
        256: "GOTO", //256
        512: "COMMENT" //512
      }
      var SwiftGotoMethod = {
        BREAK: "BREAK",
        CONTINUE: "CONTINUE",
        END: "END"
      }
      var SwiftContext = function(type, id, name) {
        this.type = type;
        this.id = id;
        this.name = name;
    
      };
      var SwiftEntity = {
        Object: {
          $this: {}
        },
        Array: {
          $data: {}[0],
          $index: 0,
          $length: {
            length: 0
          }
        }
    
      };
      var _swiftContextManager = (function SwiftContextManager() {
        var sct = SwiftContextType;
        var contexts = {};
        contexts[sct.DOCUMENT] = {
          contextType: sct.DOCUMENT,
          innerContextTypes: [sct.CONSTANT, sct.EXECUTABLE],
          ignoreStartValue: true,
          ignoreEndValue: true,
          mustHas: true
    
        },
        contexts[sct.CONSTANT] = {
          contextType: sct.CONSTANT,
          ignoreEndValue: true
        },
        contexts[sct.EXECUTABLE] = {
          contextType: sct.EXECUTABLE,
          innerContextTypes: [sct.VARIABLE, sct.FUNCTION, sct.BLOCK, sct.COMMENT],
          ignoreStartValue: true,
          ignoreEndValue: true,
          minInnerContext: 1,
          maxInnerContext: 1
        },
        contexts[sct.VARIABLE] = {
          contextType: sct.VARIABLE,
          innerContextTypes: [sct.VARIABLE, sct.CONSTANT],
          ignoreEndValue: true
        },
        contexts[sct.FUNCTION] = {
          contextType: sct.FUNCTION,
          innerContextTypes: [sct.FUNCTION, sct.VARIABLE, sct.CONSTANT],
          ignoreEndValue: true,
          minInnerContext: 1,
          maxInnerContext: 1
        },
        contexts[sct.BLOCK] = {
          contextType: sct.BLOCK,
          innerContextTypes: [sct.CONDITION, sct.CONSTANT, sct.GOTO, sct.EXECUTABLE, sct.COMMENT],
          ignoreEndValue: true,
          minInnerContext: 1,
          newScope: false,
          publicProps: ["newScope"]
        },
        contexts[sct.CONDITION] = {
          contextType: sct.CONDITION,
          innerContextTypes: [sct.FUNCTION, sct.VARIABLE, sct.CONSTANT],
          ignoreEndValue: true,
          mustHas: true,
          onceOnly: true,
          maxInnerContext: 1
        },
        contexts[sct.ENDBLOCK] = {
          contextType: sct.ENDBLOCK,
          innerContextTypes: [sct.FUNCTION, sct.VARIABLE, sct.CONSTANT],
          ignoreEndValue: true,
          mustHas: true,
          maxInnerContext: 1
        },
        contexts[sct.GOTO] = {
          contextType: sct.GOTO,
          innerContextTypes: [sct.FUNCTION, sct.VARIABLE, sct.CONSTANT],
          ignoreEndValue: true,
          maxInnerContext: 1,
          gotoMethod: SwiftGotoMethod.END,
          publicProps: ["gotoMethod"]
        },
        contexts[sct.COMMENT] = {
          contextType: sct.COMMENT,
          ignoreStartValue: true,
          ignoreEndValue: true,
          ignore: true
        };
    
        var newContext = {};
        (function init() {
          for (var type in contexts) {
            var context = contexts[type];
            var typeName = SwiftContextTypeName[type];
            var className = "Swift" + typeName[0].toUpperCase() + typeName.substring(1).toLowerCase();
            newContext[type] = (Function("return (function " + className + "() {});")());
            newContext[type].prototype = context;
            context.newC = function() {
              return newC(this);
            };
          }
        }());
    
        var getContextInfo = function(type) {
          return contexts[type];
        };
        var newC = function(context) {
          return new newContext[context.contextType];
        }
        return {
          getContextInfo: getContextInfo
        };
      }());
    
      var _swiftRuleManager = (function SwiftRuleManager() {
    
        var __rules = {};
    
        //var restrictionLevel = 0;
        var addRule = function(rule) {
          if (rule && typeof(rule) == 'object') {
            if (isNaN(rule.priority)) {
              __rules[rule.contextType].push(rule);
            } else {
              __rules[rule.contextType].splice(rule.priority, 0, rule);
            }
          }
        };
    
        var getRules = function(contextType, outerContextType, outerRuleId) {
          var rulesFirstClass = [];
          var rulesSecondClass = [];
          if (__rules[contextType]) {
            for (var priority in __rules[contextType]) {
              var rule = __rules[contextType][priority];
              if (rule.outerContextTypes & outerContextType) {
                if (rule.outerRuleId) {
                  if (rule.outerRuleId == outerRuleId) {
                    rulesFirstClass.push(rule);
                  }
                } else {
                  rulesSecondClass.push(rule);
                }
              }
            }
          }
    
          return rulesFirstClass.concat(rulesSecondClass);
        };
        (function init() {
          var sct = SwiftContextType;
          __rules[SwiftContextType.CONSTANT] = [{
            id: "swift_constant",
            contextType: sct.CONSTANT,
            outerContextTypes: sct.DOCUMENT | sct.BLOCK,
            parsing: {
              test: function(template) {
                var regx = /^[^{][^{]*?(:?(?={{)|$)/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: result[0]
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: scope.getValue(scope.setValue(context.value)),
                  isString: true
                };
              }
            }
          }];
          __rules[SwiftContextType.EXECUTABLE] = [{
            id: "swift_executable",
            contextType: sct.EXECUTABLE,
            outerContextTypes: sct.DOCUMENT | sct.BLOCK,
            parsing: {
              test: function(template) {
                var regx = /^{{/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    ignoreValue: true
                  };
                }
                return false;
              },
              testEnd: function(template) {
                var regx = /^}}/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    ignoreValue: true
                  };
                }
                return false;
              }
            }
          }];
          __rules[SwiftContextType.VARIABLE] = [{
            id: "swift_variable_keyword_this",
            contextType: sct.VARIABLE,
            outerContextTypes: sct.EXECUTABLE | sct.FUNCTION | sct.CONDITION | sct.GOTO,
            parsing: {
              test: function(template) {
                var regx = /^\$this/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: result[0]
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: scope.getValue(SwiftScopeKeyWord.$root),
                  isString: true
                };
                return scope.getValue(SwiftScopeKeyWord.$this);
              }
    
            }
          }, {
            id: "swift_variable_keyword_root",
            contextType: sct.VARIABLE,
            outerContextTypes: sct.EXECUTABLE | sct.FUNCTION | sct.CONDITION | sct.GOTO,
            parsing: {
              test: function(template) {
                var regx = /^\$root/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: result[0]
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: scope.getValue(SwiftScopeKeyWord.$root),
                  isString: true
                };
              }
    
            }
          }, {
            id: "swift_variable",
            contextType: sct.VARIABLE,
            outerContextTypes: sct.EXECUTABLE | sct.FUNCTION | sct.CONDITION | sct.GOTO,
            parsing: {
              test: function(template) {
                var regx = /^[_$\w]+[_$\w\d]*/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: result[0]
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: scope.getValue(SwiftScopeKeyWord.$this) + "['" + context.value + "']",
                  isString: true
                };
    
              }
    
            }
          }, {
            id: "swift_variable_2",
            contextType: sct.VARIABLE,
            outerContextTypes: sct.VARIABLE,
            parsing: {
              test: function(template) {
                var regx = /^.([_$\w]+[_$\w\d]*)/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: result[1]
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: "['" + context.value + "']"
                };
              }
    
            }
          }];
          __rules[SwiftContextType.FUNCTION] = [{
            id: "swift_function",
            contextType: sct.FUNCTION,
            outerContextTypes: sct.EXECUTABLE | sct.FUNCTION | sct.CONDITION | sct.GOTO,
            parsing: {
              test: function(template) {
                var regx = /^([_$\w]+[_$\w\d]*)\(/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: result[1]
                  };
                }
                return false;
              },
              testEnd: function(template) {
                var regx = /^\)/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length
                  };
                }
                return false;
              }
            }
          }];
          __rules[SwiftContextType.BLOCK] = [{
            id: "swift_block_each",
            contextType: sct.BLOCK,
            outerContextTypes: sct.EXECUTABLE,
            newScope: {
              $list: SwiftEntity.Object.$this,
              $data: SwiftEntity.Array.$data,
              $index: SwiftEntity.Array.$index,
              $length: SwiftEntity.Array.$length
            },
            parsing: {
              test: function(template) {
                var regx = /^#each/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: "each"
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                context.newScope = true;
    
                return {
                  value: "var a = scope.__data.$this;for"
                };
              }
            }
          }, {
            id: "swift_block_if",
            contextType: sct.BLOCK,
            outerContextTypes: sct.EXECUTABLE,
            parsing: {
              test: function(template) {
                var regx = /^#if/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: "if"
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: "+("
                };
              }
            }
          }];
          __rules[SwiftContextType.CONDITION] = [{
            id: "swift_condition_if",
            outerRuleId: "swift_block_if",
            contextType: sct.CONDITION,
            outerContextTypes: sct.BLOCK,
            parsing: {
              test: function(template) {
                var regx = /^\s+/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length
                  };
                }
                return false;
              },
              testEnd: function(template) {
                var regx = /^}}/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: "("
                };
              },
              compileEnd: function() {
                return {
                  value: ")?(''"
                };
              }
            }
          }, {
            id: "swift_condition_each",
            outerRuleId: "swift_block_each",
            contextType: sct.CONDITION,
            outerContextTypes: sct.BLOCK,
            parsing: {
              test: function(template) {
                var regx = /^\s+/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length
                  };
                }
                return false;
              },
              testEnd: function(template) {
                var regx = /^}}/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                scope.isForeach = true;
                context.ignoreInnerContext = true;
                return {
                  value: "(var index in "
                };
              },
              compileEnd: function(context, scope, innerResult) {
                scope.__data._$this = Function("scope", "return " + innerResult);
                return {
                  value: "a){ scope.__data.$this = a[index]; \
                             scope.__data.$index = index; content += ''"
                };
              }
            }
          }];
          __rules[SwiftContextType.GOTO] = [{
            id: "swift_goto_endblock_if",
            outerRuleId: "swift_block_if",
            contextType: sct.GOTO,
            outerContextTypes: sct.BLOCK,
            parsing: {
              test: function(template, outerContext, siblings) {
                var regx = new RegExp("^{{\/if\s*");
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: outerContext.value
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: "):'')"
                };
              }
            }
          }, {
            id: "swift_goto_endblock_each",
            outerRuleId: "swift_block_each",
            contextType: sct.GOTO,
            outerContextTypes: sct.BLOCK,
            parsing: {
              test: function(template, outerContext, siblings) {
                var regx = new RegExp("^{{\/each\s*");
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: outerContext.value
                  };
                }
                return false;
              }
            },
            compiling: {
              compile: function(context, scope) {
                return {
                  value: ";}"
                };
              }
            }
          }];
          __rules[SwiftContextType.COMMENT] = [{
            id: "swift_comment",
            contextType: sct.COMMENT,
            outerContextTypes: sct.EXECUTABLE,
            parsing: {
              test: function(template) {
                var regx = /^!(.*)(?=}})/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    value: result[1]
                  };
                }
                return false;
              }
            }
          }, {
            id: "swift_comment_2",
            contextType: sct.COMMENT,
            outerContextTypes: sct.EXECUTABLE,
            parsing: {
              test: function(template) {
                var regx = /^!--[\S\s]*--(?=}})/;
                var result = regx.exec(template);
                if (result) {
                  return {
                    lengthProcessed: result[0].length,
                    ignoreValue: true
                  };
                }
                return false;
              }
            }
          }];
        })();
        return {
          getRules: getRules,
          addRule: addRule
        };
      }());
    
      var _swiftParser = (function SwiftParser(contextManager, ruleManager) {
        var __contextManager = contextManager;
        var __ruleManager = ruleManager;
        var parse = function(template, contextType, ruleId) {
          var tmplObj = {
            template: template
          };
          var document = __contextManager.getContextInfo(SwiftContextType.DOCUMENT).newC();
          __parse(tmplObj, document, ruleId);
          return document;
        }
        var __parse = function(tmplObj, outerContext, ruleId) {
          outerContext.innerContexts = [];
          var countInnerContexts = 0;
          var innerContextTypes = 0;
          for (var i = 0; i < outerContext.innerContextTypes.length; i++) {
            var contextType = outerContext.innerContextTypes[i];
            var context = __contextManager.getContextInfo(contextType);
            if (context.onceOnly && (innerContextTypes & contextType))
              continue;
            var rules = __ruleManager.getRules(contextType, outerContext.contextType, ruleId);
            var matched = false;
            for (var j = 0; j < rules.length; j++) {
              var rule = rules[j];
              var parsing = rule.parsing;
              var match = parsing.test(tmplObj.template, outerContext);
              if (match) {
                context = context.newC();
                innerContextTypes += context.contextType;
                context.rule = rule;
                if (match.ignoreValue) {
                  context.ignoreStartValue = match.ignoreValue;
                } else {
                  context.ignoreStartValue = false;
                  context.value = match.value;
                }
                context.outerContext = outerContext;
                for (var i in context.requiredProps) {
                  var propertyName = context.requiredProps[i];
                  if (match[propertyName]) {
                    context[propertyName] = match[propertyName];
                  }
                }
                tmplObj.template = tmplObj.template.substring(match.lengthProcessed);
                if (context.innerContextTypes) {
                  __parse.call(this, tmplObj, context, rule.id);
                }
                if (parsing.testEnd) {
                  match = parsing.testEnd(tmplObj.template, context, outerContext);
                  if (match) {
                    if (match.ignoreValue) {
                      context.ignoreEndValue = match.ignoreValue;
                    } else {
                      context.ignoreEndValue = false;
                      context.endValue = match.value;
                    }
                    tmplObj.template = tmplObj.template.substring(match.lengthProcessed);
                  } else {
                    throw "511";
                  }
                }
                outerContext.innerContexts.push(context);
                matched = true;
                countInnerContexts++;
                i = -1;
                break;
              }
            }
            if (context.mustHas && !matched) {
              throw "523";
            }
            if (matched) {
              if (context.contextType == SwiftContextType.GOTO) {
                if (context.gotoMethod == SwiftGotoMethod.END || context.gotoMethod == SwiftGotoMethod.BREAK) {
                  break;
                }
              } else if (outerContext.maxInnerContext && outerContext.maxInnerContext == countInnerContexts) {
                break;
              }
            }
          }
          if (countInnerContexts < outerContext.minInnerContext) {
            throw "537";
          }
        }
    
        return {
          parse: parse
    
        };
      }(_swiftContextManager, _swiftRuleManager));
      SwiftScopeKeyWord = {
        $this: "$this",
        $data: "$data",
        $index: "$index",
        $length: "$length",
        $parent: "$parent",
        $children: "$children",
        $root: "$root",
        $isArray: "$isArray"
      };
    
      function SwiftScope(id) {
        this.__id = id;
        this.__data = {};
      }
    
      SwiftScope.prototype = (function(value) {
        var setValue = function(value) {
          var name = Math.floor(Math.random() * 1000 + +(new Date));
          return setNamedValue.call(this, name, value);
        };
    
        var setNamedValue = function(name, value) {
          if (SwiftScopeKeyWord.hasOwnProperty(name)) {
            //throw error
          }
          this.__data[name] = value;
          return name;
        };
        var getValue = function(name) {
          return "scope.__data['" + name + "']";
        };
    
        return {
          setValue: setValue,
          setNamedValue: setNamedValue,
          getValue: getValue
        };
    
      }());
    
      function SwiftScopeManager() {
        var __id = 0;
        var scopes = [];
        var createScope = function(entityName, parentScope, index) {
          var newScope = new SwiftScope("scope" + (__id++));
          if (parentScope) {
            parentScope.__data.$children.push(newScope);
            parentScope.__data.$children[newScope.__id] = newScope;
            newScope.__data.$parent = parentScope;
            newScope.__data.$root = scopes[0];
          } else {
            newScope.__data.$root = newScope;
          }
          newScope.__data.$data = entityName;
          newScope.__data.$children = [];
          if (index != undefined) {
            newScope.__data.$index = index;
          }
    
          newScope.__data.$isArray = entityName + " instanceof Array";
          newScope.__data.$length = entityName + ".length";
          scopes.push(newScope);
    
          return newScope;
        }
        var activate = function(entity) {
          scopes[0].__data.$this = entity;
          activateChildren(scopes[0]);
          return scopes[0];
        };
        var activateChildren = function(scope) {
          for (var i = 0; i < scope.__data.$children.length; i++) {
            var childScope = scope.__data.$children[i];
            childScope.__data.$this = childScope.__data._$this(scope);
            activateChildren(childScope);
          }
        };
        return {
          createScope: createScope,
          activate: activate
        }
      };
      _swiftCompiler = (function SwiftCompiler(parser) {
        var parser = parser;
        var __compile = function(context, entityName, scope, scopeManager) {
          var head = "";
          var body = "''";
          var foot = "''";
          var content = "";
    
          var rule = context.rule;
          if (!context.ignoreStartValue) {
            var result = rule.compiling.compile(context, scope);
            var concat = "";
            if (result.isString) {
              if (scope.hasContent) {
                concat = "+"
              } else {
                scope.hasContent = true;
                concat = "";
              }
            } else {
              concat = "";
            }
            content = concat + result.value;
          }
          if (context.newScope) {
            scope = scopeManager.createScope(entityName, scope);
          }
          var innerContexts = context.innerContexts;
          var innerResult = "";
          if (innerContexts && innerContexts.length) {
            for (var i = 0; i < innerContexts.length; i++) {
              if (innerContexts[i].ignore) continue;
              innerResult += __compile(innerContexts[i], entityName, scope, scopeManager);
            }
            if (!context.ignoreInnerContext)
              content += innerResult;
          }
          if (!context.ignoreEndValue) {
            var result = rule.compiling.compileEnd(context, scope, innerResult);
            var concat = "";
            if (result.isString) {
              if (scope.hasContent) {
                concat = "+"
              } else {
                scope.hasContent = true;
                concat = "";
              }
            } else {
              concat = "";
            }
            content += concat + result.value;
          }
    
          if (context.contextType === SwiftContextType.DOCUMENT) {
            content = "return (function (" + entityName + ") {var scope = scopeManager.activate(" + entityName + ");" + " return (" + content + "); });";
            console.log(content);
            return Function(entityName, "scopeManager", content)(entityName, scopeManager);
    
          }
          if (context.newScope) {
            console.log(content);
            var scopeData = "scope.__data.$children." + scope.__id;
            var preset = "";
            if (scope.__data.$parent && scope.__data.$parent.isForeach) {
              preset = scopeData + ".__data.$this = " + scopeData + ".__data._$this(scope),";
            }
            return "+(" + preset + "(function(scope){ var content = '';" + content + " return content;}(" + scopeData + ")))";
          }
    
          return content;
        };
        var compile = function(template) {
          var document = parser.parse(template);
          scopeManager = new SwiftScopeManager();
          return __compile(document, "__entity", scopeManager.createScope("__entity"), scopeManager);
        };
        return {
          compile: compile
        };
    
      }(_swiftParser));
    
      _processorManager = (function ProcessorManager() {
        var __processors = []
        var addProcessor = function() {
    
        }
        var getProcessor = function() {
          return {
            process: function(doSomething) {
              return doSomething();
            }
          }
        };
        return {
    
    
        }
      })();
    
      function HeapHandle(identifier, heapManager) {
        this.identifier = identifier;
        this.heapManager = heapManager;
    
      }
      HeapHandle.prototype = (function() {
        var toString = function() {
          return this.heapManager + "['" + this.identifier + "']";
        };
        return {
          toString: toString
        };
      })();
    
      function HeapManager() {
        this.$this = null;
    
    
      }
    
      HeapManager.prototype = (function() {
        function getGUID() {
          return Math.round(Math.random() * 1000) + +(new Date());
        }
        var addObj = function(obj, identifier) {
          if (!identifier) {
            identifier = getGUID();
          }
          this[identifier] = obj;
          return new HeapHandle(identifier, 'heapManager');
        }
        var updateObj = function(obj, identifier) {
          this[identifier] = obj;
          return new HeapHandle(identifier, 'heapManager');
        };
        var getObj = function(identifier) {
          return new HeapHandle(identifier, 'heapManager');
        };
        return {
          addObj: addObj,
          updateObj: updateObj,
          getObj: getObj
        };
      })();
    
    
      //function Compiler(ruleManager, processor) {
      //    this.processorManager = processor;
      //    this.ruleManager = ruleManager;
      //    this.parser = new Parser(ruleManager);
      //}
    
      //Compiler.prototype = (function () {
      //    //main logic for compilation, internal use only
      //    //swiftScript (SwiftScript)
      //    //return (function): template function 
      //    var __compile = function (contexts, heapManager) {
      //        var content = "return ";
      //        for (var i = 0; i < contexts.length; i++) {
      //            var context = contexts[i];
      //            if (context.rule.contextId == RuleContext.COMMENT) continue;
      //            var compiling = context.rule.compiling;
      //            if (compiling.compile) {
      //                content += compiling.compile(context.value, heapManager);
      //                content += '+';
      //            }
      //            var innerContextsResult;
      //            if (context.innerContexts) {
      //                innerContextsResult = __compile.call(this, context.innerContexts, heapManager);
      //            }
      //            if (compiling.endCompile) {
      //                content += compiling.endCompile(innerContextsResult, heapManager);
      //                content += '+';
      //            }
      //        }
      //        if (content.lastIndexOf("+") == content.length - 1 || content == "return ") {
      //            content = content.substring(0, content.length - 1);
      //            content += ";"
      //        }
      //        var func = Function('heapManager', content);
      //        console.log(func);
      //        return function (entity) {
      //            var managerHandle = heapManager.addObj(heapManager, '$manager');
      //            heapManager.updateObj(entity, '$this');
      //            return func(heapManager);
      //        };
      //    };
    
      //    //receive a template parse it, compile to javascript template
      //    //swiftTemplate (string)
      //    var compile = function (swiftTemplate) {
      //        var contexts = this.parser.parse(swiftTemplate);
      //        var heapManager = new HeapManager();
      //        var compiledTemplate = __compile(contexts, heapManager);
      //        return function (entity) {
      //            return compiledTemplate(entity);
      //        };
      //    };
    
    
      //    return {
      //        compile: compile
      //    };
    
      //})();
    
    
    
    
    
    
    
    
      function SwiftScript() {
    
      }
    
      //processors to parse or compile template
      var _processors = [];
    
      //compiler to compile parsing result to final template
      //var _compiler = new Compiler(_swiftRuleManager, _processorManager);
    
    
    
    
    
    
    
      //export functions
      var __swift = (function(compiler, paser) {
        return {
          compile: function() {
            return compiler.compile.apply(compiler, arguments);
          },
          parse: function(swiftTemplate, contextIds, outerContextId) {
            return paser.parse.call(_swiftParser, swiftTemplate);
          },
          util: _utility
        };
    
      })(_swiftCompiler, _swiftParser);
      window.swift = __swift;
    })(window);
    
    
    var test_text_1 = $(".test_text_1").html();
    var test_text_2 = $(".test_text_4").html();
    var sp = swift.compile(test_text_1);
    var hp = Handlebars.compile(test_text_1);
    var sp2 = swift.compile(test_text_2);
    var hp2 = Handlebars.compile(test_text_2);

Test runner

Ready to run.

Testing in
TestOps/sec
swift test 1
swift.compile(test_text_1)({
  HelloWorld: "123"
});
ready
handlebar test 1
Handlebars.compile(test_text_1)({
  HelloWorld: "123"
});
ready
swift test 1 precompile
sp({
  HelloWorld: "123"
});
ready
handlebar test 1 precompile
hp({
  HelloWorld: "123"
});
ready
swift test 2 precompile
sp2({
  HelloWorld: "123",
  a: {
    b: {
      c: "456"
    }
  }
});
ready
handlebar test 2 precompile
hp2({
  HelloWorld: "123",
  a: {
    b: {
      c: "456"
    }
  }
});
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.