Regexp vs Parser - Phase 2

JavaScript performance comparison

Test case created by Jamie Hill

Info

Comparing Regexp vs Parser with slight tweaks;

Preparation code

 
<script>
Benchmark.prototype.setup = function() {
    var Rule,
        openRe = /((([\*\@\#\.\w\d])([\s\*\@\#\.\w\d\-\,\>\:\=\"\~\^\$\(\)\+]*))\{)\s*/,
        closeRe = /\s*\}/;
   
    Rule = (function() {
      function Rule(source, selector, start, declarationStart, end, declarationEnd) {
        this.source = source;
        this.selector = selector;
        this.start = start;
        this.declarationStart = declarationStart;
        this.end = end || null;
        this.declarationEnd = declarationEnd || null;
        this.nested = [];
      }
   
      return Rule;
    }());
};
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Real Parser
function parser(css) {
  var length = css.length, stack = [], context, nested, match, open, close, rule, rules,
      state = 'before-selector', buffer = 0, name, i = 0, char, nested, start;

  this.cssText = css;
  this.rules = rules = context = [];

  while (char = css.charAt(i++)) {          
    switch(char) {
    case ' ':
    case '\t':
    case '\r':
    case '\n':
    case '\f':
      if (state === 'selector') { buffer++; }
      break;
    case '{':
      if (state === 'selector') {
        start = i - buffer - 1;
        rule = new Rule(css, css.slice(start, i - 1).trim(), start, i);
        context.push(rule);
        stack.push(context);
        context = rule.nested;

        state = 'before-selector'
        buffer = 0;
      }
      break;
    case ';':
      if (state === 'selector') {
        state = 'before-selector';
        buffer = 0;
      }
      break;
    case '}':
      if (state === 'before-selector') {
        context = stack.pop();
        rule = context[context.length - 1];
        if (rule) {
          rule.end = i;
          rule.declarationEnd = i - 1;
        } else {
          console.log('Closing unopened rule');
        }
        state = "before-selector";
        buffer = 0;
      }
      break;
    default:
      if (state === 'before-selector') {
        state = 'selector';
      }
      buffer++;
      break;
    }
  }

  return rules;
}

var result = parser("h1 {\n  color: red;\n  }\n\n  .some-class {\n  color: #ff0;\n  background: #f00;\n\n  .nested {\n  color: blue;\n\n  .another {\n    background: pink;\n  }\n  }\n  }");
pending…
Regex Parser
function parser(css) {
  var length = css.length, stack = [], context, nested, match, open, close, rule, rules;
 
  this.cssText = css;
  this.rules = rules = context = [];

  while (css) {
    open = css.indexOf('{');
    close = css.indexOf('}');
 
    if (open >= 0 && (close == -1 || open < close) && (match = css.match(openRe))) {
      css = css.slice(open + 1);
      rule = new Rule(this.cssText, match[2].trim(),
                      length - css.length - match[1].length, length - css.length);
      context.push(rule);
      stack.push(context);
      context = rule.nested;
    } else if (close >= 0 && (open == -1 || close < open) && (match = css.match(closeRe))) {
      css = css.slice(close + match.length);
      context = stack.pop();
      rule = context[context.length - 1];
      if (rule) {
        rule.end = length - css.length;
        rule.declarationEnd = rule.end - match.length;
      } else {
        console.log('Closing unopened rule');
      }
    } else {
      css = null;
    }
  }

  // Pop remaining
  while (stack.length) {
    context = stack.pop();
    rule = context[context.length - 1];
    rule.end = rule.declarationEnd = length;
    console.log("Unclosed rule: '" + rule.selector + "'");
  }

  return rules;
}

var result = parser("h1 {\n  color: red;\n  }\n\n  .some-class {\n  color: #ff0;\n  background: #f00;\n\n  .nested {\n  color: blue;\n\n  .another {\n    background: pink;\n  }\n  }\n  }");
pending…

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

Compare results of other browsers

0 comments

Add a comment