lexing-number-literals

JavaScript performance comparison

Test case created by Kyle Simpson

Info

Testing different methods for lexing number literals out of a string of JS code.

Preparation code

<script>

function identifyNumbers_1(code) {
        var pattern = /[=;\/]|(?:(?:0[xXbBoO][0-9a-fA-F]+)|(?:\d+\.\d*(?:[eE][+-]?\d+)?)|(?:\.\d+(?:[eE][+-]?\d+)?)|(?:\d+(?:[eE][+-]?\d+)?))/g,
                others = [], numbers = [], match, unmatched, left_context,
                prev_match_idx = 0, next_match_idx = 0
        ;

        while (next_match_idx < code.length) {
                unmatched = "";
                pattern.lastIndex = next_match_idx;
                match = pattern.exec(code);

                if (match) {
                        prev_match_idx = next_match_idx;
                        next_match_idx = pattern.lastIndex;

                        // collect the previous string code not matched before this segment
                        if (prev_match_idx < next_match_idx - match[0].length) {
                                unmatched = code.slice(prev_match_idx,next_match_idx - match[0].length);
                        }
                }
                else {
                        prev_match_idx = next_match_idx;
                        next_match_idx = code.length;
                        unmatched = code.slice(prev_match_idx);
                        if (!unmatched) break;
                }

                if (unmatched) {
                        others.push(unmatched);
                }

                if (match) {
                        left_context = code.slice(0,next_match_idx - match[0].length);

                        // matched an operator?
                        if (match[0].match(/[=;\/]/)) {
                                others.push(match[0]);
                        }
                        else if (
                                // match looks like a number?
                                match[0].match(/(?:0[xXbBoO][0-9a-fA-F]+)|(?:\d+\.\d*(?:[eE][+-]?\d+)?)|(?:\.\d+(?:[eE][+-]?\d+)?)|(?:\d+(?:[eE][+-]?\d+)?)/) &&
                                // is actually a valid number?
                                !isNaN(match[0]) &&
                                // not attached to an identifier?
                                !left_context.match(/[^\s\(\)\[\]\{\}<>,.:;=~+\-\*\/!%&\|\?\"\']$/)
                        ){
                                numbers.push(match[0]);
                        }
                        // otherwise, nothing special
                        else {
                                others.push(match[0]);
                        }
                }
        }

        return numbers;
}

function identifyNumbers_2(code) {
        var pattern = /[=;\/]|(?:(?:0[xX][0-9a-fA-F]+)|(?:0[oO][0-7]+)|(?:0[bB][01]+)|(?:\d+\.\d*(?:[eE][+-]?\d+)?)|(?:\.\d+(?:[eE][+-]?\d+)?)|(?:\d+(?:[eE][+-]?\d+)?))/g,
                others = [], numbers = [], match, unmatched, left_context,
                prev_match_idx = 0, next_match_idx = 0
        ;

        while (next_match_idx < code.length) {
                unmatched = "";
                pattern.lastIndex = next_match_idx;
                match = pattern.exec(code);

                if (match) {
                        prev_match_idx = next_match_idx;
                        next_match_idx = pattern.lastIndex;

                        // collect the previous string code not matched before this segment
                        if (prev_match_idx < next_match_idx - match[0].length) {
                                unmatched = code.slice(prev_match_idx,next_match_idx - match[0].length);
                        }
                }
                else {
                        prev_match_idx = next_match_idx;
                        next_match_idx = code.length;
                        unmatched = code.slice(prev_match_idx);
                        if (!unmatched) break;
                }

                if (unmatched) {
                        others.push(unmatched);
                }

                if (match) {
                        left_context = code.slice(0,next_match_idx - match[0].length);

                        // matched an operator?
                        if (match[0].match(/[=;\/]/)) {
                                others.push(match[0]);
                        }
                        else if (
                                // match looks like a number?
                                match[0].match(/(?:0[xX][0-9a-fA-F]+)|(?:0[oO][0-7]+)|(?:0[bB][01]+)|(?:\d+\.\d*(?:[eE][+-]?\d+)?)|(?:\.\d+(?:[eE][+-]?\d+)?)|(?:\d+(?:[eE][+-]?\d+)?)/) &&
                                // not attached to an identifier?
                                !left_context.match(/[^\s\(\)\[\]\{\}<>,.:;=~+\-\*\/!%&\|\?\"\']$/)
                        ){
                                numbers.push(match[0]);
                        }
                        // otherwise, nothing special
                        else {
                                others.push(match[0]);
                        }
                }
        }

        return numbers;
}


var test_code = "\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a=0x42;\n\
   /a/g;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   a=0x42;\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   a='foo';\n\
   a=0x42;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a='foo';\n\
   /a/g;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a=0x42;\n\
   a=0x42;\n\
   a='foo';\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a='foo';\n\
   a='foo';\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=0x42;\n\
   a='foo';\n\
   a='foo';\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   a='foo';\n\
   a='foo';\n\
   a=0x42;\n\
   o=42+a['foo'].b-e;\n\
   a=42;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=0x42;\n\
   a=a42;\n\
   /a/g;\n\
   a='foo';\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a=0x42;\n\
   a=-42;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a='foo';\n\
   a=042;\n\
   a=0x42;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   a='foo';\n\
   a=042;\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   a=.42;\n\
   /a/g;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   a=042;\n\
   /a/g;\n\
   /a/g;\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   a=0.42;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   a=042;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   a=42.;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   a=42.3;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   a=42.3.a;\n\
   a=42..a;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   /a/g;\n\
   a=042;\n\
   a=42e3;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   a=042;\n\
   /a/g;\n\
   /a/g;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=a42;\n\
   /a/g;\n\
   a=042;\n\
   a=42.e3;\n\
   a=.42e3;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   /a/g;\n\
   /a/g;\n\
   /a/g;\n\
   a='foo';\n\
   /a/g;\n\
   a='foo';\n\
   /a/g;\n\
   a=042;\n\
   a='foo';\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a='foo';\n\
   /a/g;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   /a/g;\n\
   a=042;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   a=42e-3;\n\
   a=a42;\n\
   a=042;\n\
   /a/g;\n\
   /a/g;\n\
   a='foo';\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a=42.e-3;\n\
   a=042;\n\
   /a/g;\n\
   a='foo';\n\
   a=a42;\n\
   a='foo';\n\
   /a/g;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   a='foo';\n\
   a=042;\n\
   /a/g;\n\
   a=0xaa;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a='foo';\n\
   a=042;\n\
   a='foo';\n\
   a=0x42;\n\
   a=a42;\n\
   /a/g;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   a='foo';\n\
   /a/g;\n\
   a=042;\n\
   a=a42;\n\
   a=0x42;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a=042;\n\
   a='foo';\n\
   a='foo';\n\
   a=0x42;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   a=042;\n\
   /a/g;\n\
   a=042;\n\
   /a/g;\n\
   a=0x42;\n\
   /a/g;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   a=042;\n\
   a='foo';\n\
   a=a42;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   a=0x42;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   a='foo';\n\
   a=a42;\n\
   a='foo';\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   o=42+a['foo'].b-e;\n\
   a=042;\n\
   o=42+a['foo'].b-e;\n\
   /a/g;\n\
   a=042;\n\
   a='foo';\n\
"
;

var numbers;

</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
close regex+isNaN
numbers = identifyNumbers_1(test_code);
pending…
explicit regex
numbers = identifyNumbers_2(test_code);
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