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

Unified Diff: pkg/yaml/lib/src/loader.dart

Issue 689513002: Rewrite the pkg/yaml parser. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes Created 6 years, 1 month 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 | « pkg/yaml/lib/src/event.dart ('k') | pkg/yaml/lib/src/model.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/yaml/lib/src/loader.dart
diff --git a/pkg/yaml/lib/src/loader.dart b/pkg/yaml/lib/src/loader.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d80578fc95cf9c3fb9780b577cfdbdbcdecfa261
--- /dev/null
+++ b/pkg/yaml/lib/src/loader.dart
@@ -0,0 +1,257 @@
+// 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: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 = _parseString(scalar);
+ } else if (scalar.tag != null) {
+ node = _parseByTag(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);
+ }
+
+ _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": 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);
+ }
+ throw new YamlException('Undefined tag: ${scalar.tag}.', scalar.span);
+ }
+
+ /// Parses a null scalar.
+ YamlScalar _parseNull(ScalarEvent scalar) {
+ // TODO(nweiz): stop using regexps.
+ // TODO(nweiz): add ScalarStyle and implicit metadata to the scalars.
+ if (new RegExp(r"^(null|Null|NULL|~|)$").hasMatch(scalar.value)) {
+ return new YamlScalar.internal(null, scalar.span, scalar.style);
+ } else {
+ return null;
+ }
+ }
+
+ /// Parses a boolean scalar.
+ YamlScalar _parseBool(ScalarEvent scalar) {
+ var match = new RegExp(r"^(?:(true|True|TRUE)|(false|False|FALSE))$").
+ 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 = new RegExp(r"^[-+]?[0-9]+$").firstMatch(scalar.value);
+ if (match != null) {
+ return new YamlScalar.internal(
+ int.parse(match.group(0)), scalar.span, scalar.style);
+ }
+
+ match = new RegExp(r"^0o([0-7]+)$").firstMatch(scalar.value);
+ if (match != null) {
+ var n = int.parse(match.group(1), radix: 8);
+ return new YamlScalar.internal(n, scalar.span, scalar.style);
+ }
+
+ match = new RegExp(r"^0x[0-9a-fA-F]+$").firstMatch(scalar.value);
+ if (match != null) {
+ return new YamlScalar.internal(
+ int.parse(match.group(0)), scalar.span, scalar.style);
+ }
+
+ return null;
+ }
+
+ /// Parses a floating-point scalar.
+ YamlScalar _parseFloat(ScalarEvent scalar) {
+ var match = new RegExp(
+ r"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$").
+ 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 = new RegExp(r"^([+-]?)\.(inf|Inf|INF)$").firstMatch(scalar.value);
+ if (match != null) {
+ var value = match.group(1) == "-" ? -double.INFINITY : double.INFINITY;
+ return new YamlScalar.internal(value, scalar.span, scalar.style);
+ }
+
+ match = new RegExp(r"^\.(nan|NaN|NAN)$").firstMatch(scalar.value);
+ if (match != null) {
+ return new YamlScalar.internal(double.NAN, scalar.span, scalar.style);
+ }
+
+ return null;
+ }
+
+ /// Parses a string scalar.
+ YamlScalar _parseString(ScalarEvent scalar) =>
+ new YamlScalar.internal(scalar.value, scalar.span, scalar.style);
+}
« no previous file with comments | « pkg/yaml/lib/src/event.dart ('k') | pkg/yaml/lib/src/model.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698