Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(638)

Unified Diff: lib/src/loader.dart

Issue 1325053002: - Remove scanning by regular expression and redundant scanning. (Closed) Base URL: git@github.com:dart-lang/yaml.git@master
Patch Set: Updated to df28edda6846b052d75aea0585b8d8aa250d96f2 Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/loader.dart
diff --git a/lib/src/loader.dart b/lib/src/loader.dart
index 07929579c14654eafceaa702faf0acd7dc643d5a..e1a59e1409bf0c15b3aaeb7fd986e1301d5a3763 100644
--- a/lib/src/loader.dart
+++ b/lib/src/loader.dart
@@ -13,30 +13,10 @@ import 'yaml_document.dart';
import 'yaml_exception.dart';
import 'yaml_node.dart';
-/// Matches YAML null.
-final _nullRegExp = new RegExp(r"^(null|Null|NULL|~|)$");
-
-/// Matches a YAML bool.
-final _boolRegExp = new RegExp(r"^(?:(true|True|TRUE)|(false|False|FALSE))$");
-
-/// Matches a YAML decimal integer like `+1234`.
-final _decimalIntRegExp = new RegExp(r"^[-+]?[0-9]+$");
-
-/// Matches a YAML octal integer like `0o123`.
-final _octalIntRegExp = new RegExp(r"^0o([0-7]+)$");
-
-/// Matches a YAML hexidecimal integer like `0x123abc`.
-final _hexIntRegExp = new RegExp(r"^0x[0-9a-fA-F]+$");
-
-/// Matches a YAML floating point number like `12.34+e56`.
-final _floatRegExp = new RegExp(
- r"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$");
-
-/// Matches YAML infinity.
-final _infinityRegExp = new RegExp(r"^([+-]?)\.(inf|Inf|INF)$");
-
-/// Matches YAML NaN.
-final _nanRegExp = new RegExp(r"^\.(nan|NaN|NAN)$");
+// A singleton class which corresponds to no value having been scanned.
+class _NoValue {
+ const _NoValue();
+}
/// A loader that reads [Event]s emitted by a [Parser] and emits
/// [YamlDocument]s.
@@ -133,15 +113,11 @@ class Loader {
YamlNode _loadScalar(ScalarEvent scalar) {
var node;
if (scalar.tag == "!") {
- node = _parseString(scalar);
+ node = new YamlScalar.internal(scalar.value, scalar.span, scalar.style);
} else if (scalar.tag != null) {
- node = _parseByTag(scalar);
+ node = _scanByTag(scalar);
} else {
- node = _parseNull(scalar);
- if (node == null) node = _parseBool(scalar);
- if (node == null) node = _parseInt(scalar);
- if (node == null) node = _parseFloat(scalar);
- if (node == null) node = _parseString(scalar);
+ node = _scanScalar(scalar);
}
_registerAnchor(scalar.anchor, node);
@@ -194,85 +170,189 @@ class Loader {
return node;
}
+ // Value returned by the scanning functions if no valid value was scanned.
+ static const _kNoValue = const _NoValue();
+
/// Parses a scalar according to its tag name.
- YamlScalar _parseByTag(ScalarEvent scalar) {
+ YamlScalar _scanByTag(ScalarEvent scalar) {
+ var str = scalar.value;
+ var len = str.length;
+ var ch0 = (len == 0) ? null : str.codeUnitAt(0);
+
+ var value = _kNoValue;
switch (scalar.tag) {
- case "tag:yaml.org,2002:null": return _parseNull(scalar);
- case "tag:yaml.org,2002:bool": return _parseBool(scalar);
- case "tag:yaml.org,2002:int": return _parseInt(scalar);
- case "tag:yaml.org,2002:float": return _parseFloat(scalar);
- case "tag:yaml.org,2002:str": return _parseString(scalar);
+ case "tag:yaml.org,2002:null":
+ value = _scanNull(str, ch0, len);
+ break;
+ case "tag:yaml.org,2002:bool":
+ value = _scanBool(str, ch0, len);
+ break;
+ case "tag:yaml.org,2002:int":
+ value = _scanNumber(str, ch0, len, true, false);
+ break;
+ case "tag:yaml.org,2002:float":
+ value = _scanNumber(str, ch0, len, false, true);
+ break;
+ case "tag:yaml.org,2002:str":
+ value = str;
+ break;
+ default:
+ throw new YamlException('Undefined tag: ${scalar.tag}.', scalar.span);
+ }
+ if (value != _kNoValue) {
+ return new YamlScalar.internal(value, scalar.span, scalar.style);
}
- throw new YamlException('Undefined tag: ${scalar.tag}.', scalar.span);
+ return null;
}
- /// Parses a null scalar.
- YamlScalar _parseNull(ScalarEvent scalar) {
- // TODO(nweiz): add ScalarStyle and implicit metadata to the scalars.
- if (_nullRegExp.hasMatch(scalar.value)) {
- return new YamlScalar.internal(null, scalar.span, scalar.style);
+ /// Code unit values.
+ static const _plus = 0x2B;
+ static const _minus = 0x2D;
+ static const _dot = 0x2E;
+ static const _0 = 0x30;
+ static const _9 = 0x39;
+ static const _F = 0x46;
+ static const _N = 0x4E;
+ static const _T = 0x54;
+ static const _f = 0x66;
+ static const _n = 0x6E;
+ static const _o = 0x6F;
+ static const _t = 0x74;
+ static const _x = 0x78;
+ static const _tilde = 0x7E;
+
+ /// Scan a scalar event's value.
+ YamlScalar _scanScalar(ScalarEvent scalar) {
+ final str = scalar.value;
+ final len = str.length;
+ final span = scalar.span;
+ final style = scalar.style;
+
+ var value = _kNoValue;
+
+ // Quickly check for the empty string.
+ if (len == 0) {
+ // Empty string is equivalent to null.
+ value = null;
} else {
- return null;
+ // Dispatch on the first character.
+ var ch0 = str.codeUnitAt(0);
+ if ((ch0 == _dot) || (ch0 == _plus) || (ch0 == _minus) ||
+ ((ch0 >= _0) && (ch0 <= _9))) {
+ // Recognize numbers (either int or double).
+ value = _scanNumber(str, ch0, len, true, true);
+ } else if ((len == 4) && ((ch0 == _n) || (ch0 == _N))) {
+ value = _scanNull(str, ch0, len);
+ } else if (((len == 4) && ((ch0 == _t) || (ch0 == _T))) ||
+ ((len == 5) && ((ch0 == _f) || (ch0 == _F)))) {
+ value = _scanBool(str, ch0, len);
+ } else if ((len == 1) && (ch0 == _tilde)) {
+ // Special case of null be written as "~'.
+ value = null;
+ }
}
- }
- /// Parses a boolean scalar.
- YamlScalar _parseBool(ScalarEvent scalar) {
- var match = _boolRegExp.firstMatch(scalar.value);
- if (match == null) return null;
- return new YamlScalar.internal(
- match.group(1) != null, scalar.span, scalar.style);
- }
-
- /// Parses an integer scalar.
- YamlScalar _parseInt(ScalarEvent scalar) {
- var match = _decimalIntRegExp.firstMatch(scalar.value);
- if (match != null) {
- return new YamlScalar.internal(
- int.parse(match.group(0)), scalar.span, scalar.style);
+ // If no value was found, set to the String value.
+ if (value == _kNoValue) {
+ value = str;
}
+ return new YamlScalar.internal(value, span, style);
+ }
- match = _octalIntRegExp.firstMatch(scalar.value);
- if (match != null) {
- var n = int.parse(match.group(1), radix: 8);
- return new YamlScalar.internal(n, scalar.span, scalar.style);
+ /// Scan the different versions of the null literal.
+ _scanNull(String str, int ch0, int len) {
+ if (len == 4) {
+ if (((ch0 == _n) && (str == "null")) ||
+ ((ch0 == _N) && ((str == "Null") || (str == "NULL")))) {
+ return null;
+ }
+ } else if ((len == 0) || ((len == 1) && (ch0 == _tilde))) {
+ return null;
}
+ return _kNoValue;
+ }
- match = _hexIntRegExp.firstMatch(scalar.value);
- if (match != null) {
- return new YamlScalar.internal(
- int.parse(match.group(0)), scalar.span, scalar.style);
+ /// Scan a boolean.
+ _scanBool(String str, int ch0, int len) {
+ if (len == 4) {
+ if (((ch0 == _t) && (str == "true")) ||
+ ((ch0 == _T) && ((str == "True") || (str == "TRUE")))) {
+ return true;
+ }
+ } else if (len == 5) {
+ if (((ch0 == _f) && (str == "false")) ||
+ ((ch0 == _F) && ((str == "False") || (str == "FALSE")))) {
+ return false;
+ }
}
-
- return null;
+ return _kNoValue;
}
- /// Parses a floating-point scalar.
- YamlScalar _parseFloat(ScalarEvent scalar) {
- var match = _floatRegExp.firstMatch(scalar.value);
- if (match != null) {
- // YAML allows floats of the form "0.", but Dart does not. Fix up those
- // floats by removing the trailing dot.
- var matchStr = match.group(0).replaceAll(new RegExp(r"\.$"), "");
- return new YamlScalar.internal(
- double.parse(matchStr), scalar.span, scalar.style);
- }
- match = _infinityRegExp.firstMatch(scalar.value);
- if (match != null) {
- var value = match.group(1) == "-" ? -double.INFINITY : double.INFINITY;
- return new YamlScalar.internal(value, scalar.span, scalar.style);
- }
+ /// Helper which returns the known "no value" when number parsing fails.
+ static var _onNumError = (_) => null;
- match = _nanRegExp.firstMatch(scalar.value);
- if (match != null) {
- return new YamlScalar.internal(double.NAN, scalar.span, scalar.style);
+ /// Scan a number. Handles both integers and floats within one function if
+ /// possible avoid rescanning in the general case.
+ _scanNumber(String str, int ch0, int len, bool allow_int, bool allow_float) {
+ // Quick check for single digit integers.
+ if (len == 1) {
+ var val = ch0 - _0;
+ if ((val >= 0) && (val <= 9)) {
+ return val;
+ }
+ return _kNoValue;
}
-
- return null;
+ // Assume we are scanning a nicely formed number.
+ var ch1 = str.codeUnitAt(1);
+ if (allow_int && (ch0 == _0) && ((ch1 == _x) || (ch1 == _o))) {
+ // Scanning hex or octal integers.
+ var sub_str = str.substring(2);
+ if (ch1 == _x) {
+ var result = int.parse(sub_str, radix:16, onError: _onNumError);
+ return (result != null) ? result : _kNoValue;
+ }
+ var result = int.parse(sub_str, radix: 8, onError: _onNumError);
+ return (result != null) ? result : _kNoValue;
+ } else if (((ch0 >= _0) && (ch0 <= _9)) ||
+ (((ch0 == _plus) || (ch0 == _minus)) &&
+ (ch1 >= _0) && (ch1 <= _9))) {
+ // Either starting with a number or starting with a sign and number.
+ var result = null;
+ if (allow_int) {
+ // Possible hex or octal numbers are handled above, so only allow
+ // radix 10 here.
+ result = int.parse(str, radix: 10, onError: _onNumError);
+ }
+ // If we failed to scan an int, try to scan as a double.
+ if (allow_float && (result == null)) {
+ result = double.parse(str, _onNumError);
+ }
+ return (result != null) ? result : _kNoValue;
+ } else if (allow_float) {
+ // Not the only possibility is to scan a float starting with a dot or
+ // a sign and a dot. As well as the signed/unsigned infinity values and
+ // not-a-numbers.
+ if (((ch0 == _dot) && (ch1 >= _0) && (ch1 <= _9)) ||
+ ((ch0 == _minus) || (ch0 == _plus)) && (ch1 == _dot)) {
+ // Starting with a . and a number or a sign followed by a dot.
+ if (len == 5) {
+ if (str == "+.inf" || str == "+.Inf" || str == "+.INF") {
+ return double.INFINITY;
+ } else if (str == "-.inf" || str == "-.Inf" || str == "-.INF") {
+ return -double.INFINITY;
+ }
+ }
+ var result = double.parse(str, _onNumError);
+ return (result != null) ? result : _kNoValue;
+ } else if ((len == 4) && (ch0 == _dot)) {
+ if (str == ".inf" || str == ".Inf" || str == ".INF") {
+ return double.INFINITY;
+ } else if (str == ".nan" || str == ".NaN" || str == ".NAN") {
+ return double.NAN;
+ }
+ }
+ }
+ return _kNoValue;
}
-
- /// Parses a string scalar.
- YamlScalar _parseString(ScalarEvent scalar) =>
- new YamlScalar.internal(scalar.value, scalar.span, scalar.style);
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698