Skip to content

Commit 626137c

Browse files
committed
Rewrite parser_input to not use String.substring
Instead use RegExp.matchAsPrefix(...) - which was optimized on the bleeding edge Dart VM to perform a sticky match. Benchmark (bleeding edge Dart VM x64): 48xx ms -> 7xx ms (almost 7x).
1 parent 7246fe9 commit 626137c

File tree

4 files changed

+108
-454
lines changed

4 files changed

+108
-454
lines changed

lib/src/parser/entities.dart

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class Entities {
5656
// },
5757
}
5858

59-
static final RegExp _keywordRegEx = new RegExp(r'^[_A-Za-z-][_A-Za-z0-9-]*', caseSensitive: true);
59+
static final RegExp _keywordRegEx = new RegExp(r'[_A-Za-z-][_A-Za-z0-9-]*', caseSensitive: true);
6060
///
6161
/// A catch-all word, such as:
6262
///
@@ -81,7 +81,8 @@ class Entities {
8181
// },
8282
}
8383

84-
static final _callRegExp = new RegExp(r'^([\w-]+|%|progid:[\w\.]+)\(', caseSensitive: true);
84+
static final _callRegExp = new RegExp(r'([\w-]+|%|progid:[\w\.]+)\(', caseSensitive: true);
85+
static final _reCallUrl = new RegExp(r'url\(', caseSensitive: false);
8586
///
8687
/// A function call
8788
///
@@ -100,7 +101,7 @@ class Entities {
100101
int index = parserInput.i;
101102

102103
// http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
103-
if (parserInput.peek(new RegExp(r'^url\(', caseSensitive: false))) return null;
104+
if (parserInput.peek(_reCallUrl)) return null;
104105

105106
parserInput.save();
106107

@@ -199,8 +200,8 @@ class Entities {
199200
// }
200201
}
201202

202-
static final _alphaRegExp1 = new RegExp(r'^\opacity=', caseSensitive: false);
203-
static final _alphaRegExp2 = new RegExp(r'^\d+', caseSensitive: true);
203+
static final _alphaRegExp1 = new RegExp(r'\opacity=', caseSensitive: false);
204+
static final _alphaRegExp2 = new RegExp(r'\d+', caseSensitive: true);
204205
///
205206
/// IE's alpha function
206207
///
@@ -285,7 +286,7 @@ class Entities {
285286
// }
286287
}
287288

288-
static final _assignmentRegExp = new RegExp(r'^\w+(?=\s?=)', caseSensitive: false);
289+
static final _assignmentRegExp = new RegExp(r'\w+(?=\s?=)', caseSensitive: false);
289290
///
290291
/// Assignments are argument entities for calls.
291292
/// They are present in ie filter properties as shown below.
@@ -340,7 +341,7 @@ class Entities {
340341
// },
341342
}
342343

343-
static final _urlRegExp = new RegExp(r'''^(?:(?:\\[\(\)'"])|[^\(\)'"])+''', caseSensitive: true);
344+
static final _urlRegExp = new RegExp(r'''(?:(?:\\[\(\)'"])|[^\(\)'"])+''', caseSensitive: true);
344345
///
345346
/// Parse url() tokens
346347
///
@@ -395,7 +396,7 @@ class Entities {
395396
// },
396397
}
397398

398-
static final _variableRegExp = new RegExp(r'^@@?[\w-]+', caseSensitive: true);
399+
static final _variableRegExp = new RegExp(r'@@?[\w-]+', caseSensitive: true);
399400
///
400401
/// A Variable entity, such as `@fink`, in
401402
///
@@ -424,7 +425,7 @@ class Entities {
424425
// }
425426
}
426427

427-
static final _variableCurlyRegExp = new RegExp(r'^@\{([\w-]+)\}', caseSensitive: true);
428+
static final _variableCurlyRegExp = new RegExp(r'@\{([\w-]+)\}', caseSensitive: true);
428429
///
429430
/// A variable entity using the protective {} e.g. @{var}
430431
///
@@ -447,9 +448,9 @@ class Entities {
447448
// }
448449
}
449450

450-
static final _colorRegExp1 = new RegExp(r'^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})', caseSensitive: true);
451+
static final _colorRegExp1 = new RegExp(r'#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})', caseSensitive: true);
451452

452-
static final _colorRegExp2 = new RegExp(r'^#([\w]+).*');
453+
static final _colorRegExp2 = new RegExp(r'#([\w]+).*');
453454
static final _colorRegExp3 = new RegExp(r'^[A-Fa-f0-9]+$');
454455

455456
///
@@ -463,11 +464,11 @@ class Entities {
463464
Match rgb;
464465

465466
if (parserInput.currentChar() == '#'
466-
&& (rgb = parserInput.$reMatchRegExp(_colorRegExp1)) != null) {
467+
&& (rgb = parserInput.$reMatch(_colorRegExp1)) != null) {
467468

468469
// strip colons, brackets, whitespaces and other characters that should not
469470
// definitely be part of color string
470-
Match colorCandidateMatch = _colorRegExp2.firstMatch(rgb.input);
471+
Match colorCandidateMatch = _colorRegExp2.matchAsPrefix(rgb.input, rgb.start);
471472
String colorCandidateString = colorCandidateMatch[1];
472473

473474
// verify if candidate consists only of allowed HEX characters
@@ -495,7 +496,7 @@ class Entities {
495496
// },
496497
}
497498

498-
static final _dimensionRegExp = new RegExp(r'^([+-]?\d*\.?\d+)(%|[a-z]+)?', caseSensitive: false);
499+
static final _dimensionRegExp = new RegExp(r'([+-]?\d*\.?\d+)(%|[a-z]+)?', caseSensitive: false);
499500
///
500501
/// A Dimension, that is, a number and a unit
501502
///
@@ -521,7 +522,7 @@ class Entities {
521522
// }
522523
}
523524

524-
static final _unicodeDescriptorRegExp = new RegExp(r'^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?', caseSensitive: true);
525+
static final _unicodeDescriptorRegExp = new RegExp(r'U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?', caseSensitive: true);
525526

526527
///
527528
/// A unicode descriptor, as is used in unicode-range
@@ -545,7 +546,7 @@ class Entities {
545546
// }
546547
}
547548

548-
static final _javascriptRegExp = new RegExp(r'^[^`]*`', caseSensitive: true);
549+
static final _javascriptRegExp = new RegExp(r'[^`]*`', caseSensitive: true);
549550

550551
///
551552
/// JavaScript code to be evaluated

lib/src/parser/mixin.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class Mixin {
1919
}
2020

2121

22-
static final _callRegExp = new RegExp(r'^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+', caseSensitive: true);
22+
static final _callRegExp = new RegExp(r'[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+', caseSensitive: true);
2323

2424
///
2525
/// A Mixin call, with an optional argument list
@@ -337,7 +337,7 @@ class Mixin {
337337
// },
338338
}
339339

340-
static final _definitionRegExp = new RegExp(r'^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(', caseSensitive: true);
340+
static final _definitionRegExp = new RegExp(r'([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(', caseSensitive: true);
341341

342342
///
343343
/// A Mixin definition, with a list of parameters
@@ -358,6 +358,7 @@ class Mixin {
358358
/// Once we've got our params list, and a closing `)`, we parse
359359
/// the `{...}` block.
360360
///
361+
static final _reDefinition = new RegExp(r'[^{]*\}');
361362
MixinDefinition definition() {
362363
Condition cond;
363364
int index = parserInput.i; //not in original
@@ -366,7 +367,7 @@ class Mixin {
366367
List<Node> ruleset;
367368
bool variadic = false;
368369

369-
if ((parserInput.currentChar() != '.' && parserInput.currentChar() != '#') || parserInput.peek(new RegExp(r'^[^{]*\}'))) return null;
370+
if ((parserInput.currentChar() != '.' && parserInput.currentChar() != '#') || parserInput.peek(_reDefinition)) return null;
370371

371372
parserInput.save();
372373

0 commit comments

Comments
 (0)