Index: yaml/lib/src/loader.dart |
diff --git a/yaml/lib/src/loader.dart b/yaml/lib/src/loader.dart |
deleted file mode 100644 |
index 533631041e0e884c020f5edc7f1b12485fd949c7..0000000000000000000000000000000000000000 |
--- a/yaml/lib/src/loader.dart |
+++ /dev/null |
@@ -1,359 +0,0 @@ |
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library yaml.loader; |
- |
-import 'package:charcode/ascii.dart'; |
-import 'package:source_span/source_span.dart'; |
- |
-import 'equality.dart'; |
-import 'event.dart'; |
-import 'parser.dart'; |
-import 'yaml_document.dart'; |
-import 'yaml_exception.dart'; |
-import 'yaml_node.dart'; |
- |
-/// A loader that reads [Event]s emitted by a [Parser] and emits |
-/// [YamlDocument]s. |
-/// |
-/// This is based on the libyaml loader, available at |
-/// https://github.com/yaml/libyaml/blob/master/src/loader.c. The license for |
-/// that is available in ../../libyaml-license.txt. |
-class Loader { |
- /// The underlying [Parser] that generates [Event]s. |
- final Parser _parser; |
- |
- /// Aliases by the alias name. |
- final _aliases = new Map<String, YamlNode>(); |
- |
- /// The span of the entire stream emitted so far. |
- FileSpan get span => _span; |
- FileSpan _span; |
- |
- /// Creates a loader that loads [source]. |
- /// |
- /// [sourceUrl] can be a String or a [Uri]. |
- Loader(String source, {sourceUrl}) |
- : _parser = new Parser(source, sourceUrl: sourceUrl) { |
- var event = _parser.parse(); |
- _span = event.span; |
- assert(event.type == EventType.STREAM_START); |
- } |
- |
- /// Loads the next document from the stream. |
- /// |
- /// If there are no more documents, returns `null`. |
- YamlDocument load() { |
- if (_parser.isDone) return null; |
- |
- var event = _parser.parse(); |
- if (event.type == EventType.STREAM_END) { |
- _span = _span.expand(event.span); |
- return null; |
- } |
- |
- var document = _loadDocument(event); |
- _span = _span.expand(document.span); |
- _aliases.clear(); |
- return document; |
- } |
- |
- /// Composes a document object. |
- YamlDocument _loadDocument(DocumentStartEvent firstEvent) { |
- var contents = _loadNode(_parser.parse()); |
- |
- var lastEvent = _parser.parse(); |
- assert(lastEvent.type == EventType.DOCUMENT_END); |
- |
- return new YamlDocument.internal( |
- contents, |
- firstEvent.span.expand(lastEvent.span), |
- firstEvent.versionDirective, |
- firstEvent.tagDirectives, |
- startImplicit: firstEvent.isImplicit, |
- endImplicit: lastEvent.isImplicit); |
- } |
- |
- /// Composes a node. |
- YamlNode _loadNode(Event firstEvent) { |
- switch (firstEvent.type) { |
- case EventType.ALIAS: return _loadAlias(firstEvent); |
- case EventType.SCALAR: return _loadScalar(firstEvent); |
- case EventType.SEQUENCE_START: return _loadSequence(firstEvent); |
- case EventType.MAPPING_START: return _loadMapping(firstEvent); |
- default: throw "Unreachable"; |
- } |
- } |
- |
- /// Registers an anchor. |
- void _registerAnchor(String anchor, YamlNode node) { |
- if (anchor == null) return; |
- |
- // libyaml throws an error for duplicate anchors, but example 7.1 makes it |
- // clear that they should be overridden: |
- // http://yaml.org/spec/1.2/spec.html#id2786448. |
- |
- _aliases[anchor] = node; |
- } |
- |
- /// Composes a node corresponding to an alias. |
- YamlNode _loadAlias(AliasEvent event) { |
- var alias = _aliases[event.name]; |
- if (alias != null) return alias; |
- |
- throw new YamlException("Undefined alias.", event.span); |
- } |
- |
- /// Composes a scalar node. |
- YamlNode _loadScalar(ScalarEvent scalar) { |
- var node; |
- if (scalar.tag == "!") { |
- node = new YamlScalar.internal(scalar.value, scalar); |
- } else if (scalar.tag != null) { |
- node = _parseByTag(scalar); |
- } else { |
- node = _parseScalar(scalar); |
- } |
- |
- _registerAnchor(scalar.anchor, node); |
- return node; |
- } |
- |
- /// Composes a sequence node. |
- YamlNode _loadSequence(SequenceStartEvent firstEvent) { |
- if (firstEvent.tag != "!" && firstEvent.tag != null && |
- firstEvent.tag != "tag:yaml.org,2002:seq") { |
- throw new YamlException("Invalid tag for sequence.", firstEvent.span); |
- } |
- |
- var children = []; |
- var node = new YamlList.internal( |
- children, firstEvent.span, firstEvent.style); |
- _registerAnchor(firstEvent.anchor, node); |
- |
- var event = _parser.parse(); |
- while (event.type != EventType.SEQUENCE_END) { |
- children.add(_loadNode(event)); |
- event = _parser.parse(); |
- } |
- |
- setSpan(node, firstEvent.span.expand(event.span)); |
- return node; |
- } |
- |
- /// Composes a mapping node. |
- YamlNode _loadMapping(MappingStartEvent firstEvent) { |
- if (firstEvent.tag != "!" && firstEvent.tag != null && |
- firstEvent.tag != "tag:yaml.org,2002:map") { |
- throw new YamlException("Invalid tag for mapping.", firstEvent.span); |
- } |
- |
- var children = deepEqualsMap(); |
- var node = new YamlMap.internal( |
- children, firstEvent.span, firstEvent.style); |
- _registerAnchor(firstEvent.anchor, node); |
- |
- var event = _parser.parse(); |
- while (event.type != EventType.MAPPING_END) { |
- var key = _loadNode(event); |
- var value = _loadNode(_parser.parse()); |
- children[key] = value; |
- event = _parser.parse(); |
- } |
- |
- setSpan(node, firstEvent.span.expand(event.span)); |
- return node; |
- } |
- |
- /// Parses a scalar according to its tag name. |
- YamlScalar _parseByTag(ScalarEvent scalar) { |
- switch (scalar.tag) { |
- case "tag:yaml.org,2002:null": |
- var result = _parseNull(scalar); |
- if (result != null) return result; |
- throw new YamlException("Invalid null scalar.", scalar.span); |
- case "tag:yaml.org,2002:bool": |
- var result = _parseBool(scalar); |
- if (result != null) return result; |
- throw new YamlException("Invalid bool scalar.", scalar.span); |
- case "tag:yaml.org,2002:int": |
- var result = _parseNumber(scalar, allowFloat: false); |
- if (result != null) return result; |
- throw new YamlException("Invalid int scalar.", scalar.span); |
- case "tag:yaml.org,2002:float": |
- var result = _parseNumber(scalar, allowInt: false); |
- if (result != null) return result; |
- throw new YamlException("Invalid float scalar.", scalar.span); |
- case "tag:yaml.org,2002:str": |
- return new YamlScalar.internal(scalar.value, scalar); |
- default: |
- throw new YamlException('Undefined tag: ${scalar.tag}.', scalar.span); |
- } |
- } |
- |
- /// Parses [scalar], which may be one of several types. |
- YamlScalar _parseScalar(ScalarEvent scalar) => |
- _tryParseScalar(scalar) ?? new YamlScalar.internal(scalar.value, scalar); |
- |
- /// Tries to parse [scalar]. |
- /// |
- /// If parsing fails, this returns `null`, indicating that the scalar should |
- /// be parsed as a string. |
- YamlScalar _tryParseScalar(ScalarEvent scalar) { |
- // Quickly check for the empty string, which means null. |
- var length = scalar.value.length; |
- if (length == 0) return new YamlScalar.internal(null, scalar); |
- |
- // Dispatch on the first character. |
- var firstChar = scalar.value.codeUnitAt(0); |
- switch (firstChar) { |
- case $dot: |
- case $plus: |
- case $minus: |
- return _parseNumber(scalar); |
- case $n: |
- case $N: |
- return length == 4 ? _parseNull(scalar) : null; |
- case $t: |
- case $T: |
- return length == 4 ? _parseBool(scalar) : null; |
- case $f: |
- case $F: |
- return length == 5 ? _parseBool(scalar) : null; |
- case $tilde: |
- return length == 1 ? new YamlScalar.internal(null, scalar) : null; |
- default: |
- if (firstChar >= $0 && firstChar <= $9) return _parseNumber(scalar); |
- return null; |
- } |
- } |
- |
- /// Parse a null scalar. |
- /// |
- /// Returns a Dart `null` if parsing fails. |
- YamlScalar _parseNull(ScalarEvent scalar) { |
- switch (scalar.value) { |
- case "": |
- case "null": |
- case "Null": |
- case "NULL": |
- case "~": |
- return new YamlScalar.internal(null, scalar); |
- default: |
- return null; |
- } |
- } |
- |
- /// Parse a boolean scalar. |
- /// |
- /// Returns `null` if parsing fails. |
- YamlScalar _parseBool(ScalarEvent scalar) { |
- switch (scalar.value) { |
- case "true": |
- case "True": |
- case "TRUE": |
- return new YamlScalar.internal(true, scalar); |
- case "false": |
- case "False": |
- case "FALSE": |
- return new YamlScalar.internal(false, scalar); |
- default: |
- return null; |
- } |
- } |
- |
- /// Parses a numeric scalar. |
- /// |
- /// Returns `null` if parsing fails. |
- YamlNode _parseNumber(ScalarEvent scalar, {bool allowInt: true, |
- bool allowFloat: true}) { |
- var value = _parseNumberValue(scalar.value, |
- allowInt: allowInt, allowFloat: allowFloat); |
- return value == null ? null : new YamlScalar.internal(value, scalar); |
- } |
- |
- /// Parses the value of a number. |
- /// |
- /// Returns the number if it's parsed successfully, or `null` if it's not. |
- num _parseNumberValue(String contents, {bool allowInt: true, |
- bool allowFloat: true}) { |
- assert(allowInt || allowFloat); |
- |
- var firstChar = contents.codeUnitAt(0); |
- var length = contents.length; |
- |
- // Quick check for single digit integers. |
- if (allowInt && length == 1) { |
- var value = firstChar - $0; |
- return value >= 0 && value <= 9 ? value : null; |
- } |
- |
- var secondChar = contents.codeUnitAt(1); |
- |
- // Hexadecimal or octal integers. |
- if (allowInt && firstChar == $0) { |
- // int.parse supports 0x natively. |
- if (secondChar == $x) return int.parse(contents, onError: (_) => null); |
- |
- if (secondChar == $o) { |
- var afterRadix = contents.substring(2); |
- return int.parse(afterRadix, radix: 8, onError: (_) => null); |
- } |
- } |
- |
- // Int or float starting with a digit or a +/- sign. |
- if ((firstChar >= $0 && firstChar <= $9) || |
- ((firstChar == $plus || firstChar == $minus) && |
- secondChar >= $0 && secondChar <= $9)) { |
- // Try to parse an int or, failing that, a double. |
- var result = null; |
- if (allowInt) { |
- // Pass "radix: 10" explicitly to ensure that "-0x10", which is valid |
- // Dart but invalid YAML, doesn't get parsed. |
- result = int.parse(contents, radix: 10, onError: (_) => null); |
- } |
- |
- if (allowFloat) result ??= double.parse(contents, (_) => null); |
- return result; |
- } |
- |
- if (!allowFloat) return null; |
- |
- // Now the only possibility is to parse a float starting with a dot or a |
- // sign and a dot, or the signed/unsigned infinity values and not-a-numbers. |
- if ((firstChar == $dot && secondChar >= $0 && secondChar <= $9) || |
- (firstChar == $minus || firstChar == $plus) && secondChar == $dot) { |
- // Starting with a . and a number or a sign followed by a dot. |
- if (length == 5) { |
- switch (contents) { |
- case "+.inf": |
- case "+.Inf": |
- case "+.INF": |
- return double.INFINITY; |
- case "-.inf": |
- case "-.Inf": |
- case "-.INF": |
- return -double.INFINITY; |
- } |
- } |
- |
- return double.parse(contents, (_) => null); |
- } |
- |
- if (length == 4 && firstChar == $dot) { |
- switch (contents) { |
- case ".inf": |
- case ".Inf": |
- case ".INF": |
- return double.INFINITY; |
- case ".nan": |
- case ".NaN": |
- case ".NAN": |
- return double.NAN; |
- } |
- } |
- |
- return null; |
- } |
-} |