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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/yaml/lib/src/event.dart ('k') | pkg/yaml/lib/src/model.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library yaml.loader;
6
7 import 'package:source_span/source_span.dart';
8
9 import 'equality.dart';
10 import 'event.dart';
11 import 'parser.dart';
12 import 'yaml_document.dart';
13 import 'yaml_exception.dart';
14 import 'yaml_node.dart';
15
16 /// A loader that reads [Event]s emitted by a [Parser] and emits
17 /// [YamlDocument]s.
18 ///
19 /// This is based on the libyaml loader, available at
20 /// https://github.com/yaml/libyaml/blob/master/src/loader.c. The license for
21 /// that is available in ../../libyaml-license.txt.
22 class Loader {
23 /// The underlying [Parser] that generates [Event]s.
24 final Parser _parser;
25
26 /// Aliases by the alias name.
27 final _aliases = new Map<String, YamlNode>();
28
29 /// The span of the entire stream emitted so far.
30 FileSpan get span => _span;
31 FileSpan _span;
32
33 /// Creates a loader that loads [source].
34 ///
35 /// [sourceUrl] can be a String or a [Uri].
36 Loader(String source, {sourceUrl})
37 : _parser = new Parser(source, sourceUrl: sourceUrl) {
38 var event = _parser.parse();
39 _span = event.span;
40 assert(event.type == EventType.STREAM_START);
41 }
42
43 /// Loads the next document from the stream.
44 ///
45 /// If there are no more documents, returns `null`.
46 YamlDocument load() {
47 if (_parser.isDone) return null;
48
49 var event = _parser.parse();
50 if (event.type == EventType.STREAM_END) {
51 _span = _span.expand(event.span);
52 return null;
53 }
54
55 var document = _loadDocument(event);
56 _span = _span.expand(document.span);
57 _aliases.clear();
58 return document;
59 }
60
61 /// Composes a document object.
62 YamlDocument _loadDocument(DocumentStartEvent firstEvent) {
63 var contents = _loadNode(_parser.parse());
64
65 var lastEvent = _parser.parse();
66 assert(lastEvent.type == EventType.DOCUMENT_END);
67
68 return new YamlDocument.internal(
69 contents,
70 firstEvent.span.expand(lastEvent.span),
71 firstEvent.versionDirective,
72 firstEvent.tagDirectives,
73 startImplicit: firstEvent.isImplicit,
74 endImplicit: lastEvent.isImplicit);
75 }
76
77 /// Composes a node.
78 YamlNode _loadNode(Event firstEvent) {
79 switch (firstEvent.type) {
80 case EventType.ALIAS: return _loadAlias(firstEvent);
81 case EventType.SCALAR: return _loadScalar(firstEvent);
82 case EventType.SEQUENCE_START: return _loadSequence(firstEvent);
83 case EventType.MAPPING_START: return _loadMapping(firstEvent);
84 default: throw "Unreachable";
85 }
86 }
87
88 /// Registers an anchor.
89 void _registerAnchor(String anchor, YamlNode node) {
90 if (anchor == null) return;
91
92 // libyaml throws an error for duplicate anchors, but example 7.1 makes it
93 // clear that they should be overridden:
94 // http://yaml.org/spec/1.2/spec.html#id2786448.
95
96 _aliases[anchor] = node;
97 }
98
99 /// Composes a node corresponding to an alias.
100 YamlNode _loadAlias(AliasEvent event) {
101 var alias = _aliases[event.name];
102 if (alias != null) return alias;
103
104 throw new YamlException("Undefined alias.", event.span);
105 }
106
107 /// Composes a scalar node.
108 YamlNode _loadScalar(ScalarEvent scalar) {
109 var node;
110 if (scalar.tag == "!") {
111 node = _parseString(scalar);
112 } else if (scalar.tag != null) {
113 node = _parseByTag(scalar);
114 } else {
115 node = _parseNull(scalar);
116 if (node == null) node = _parseBool(scalar);
117 if (node == null) node = _parseInt(scalar);
118 if (node == null) node = _parseFloat(scalar);
119 if (node == null) node = _parseString(scalar);
120 }
121
122 _registerAnchor(scalar.anchor, node);
123 return node;
124 }
125
126 /// Composes a sequence node.
127 YamlNode _loadSequence(SequenceStartEvent firstEvent) {
128 if (firstEvent.tag != "!" && firstEvent.tag != null &&
129 firstEvent.tag != "tag:yaml.org,2002:seq") {
130 throw new YamlException("Invalid tag for sequence.", firstEvent.span);
131 }
132
133 var children = [];
134 var node = new YamlList.internal(
135 children, firstEvent.span, firstEvent.style);
136 _registerAnchor(firstEvent.anchor, node);
137
138 var event = _parser.parse();
139 while (event.type != EventType.SEQUENCE_END) {
140 children.add(_loadNode(event));
141 event = _parser.parse();
142 }
143
144 setSpan(node, firstEvent.span.expand(event.span));
145 return node;
146 }
147
148 /// Composes a mapping node.
149 YamlNode _loadMapping(MappingStartEvent firstEvent) {
150 if (firstEvent.tag != "!" && firstEvent.tag != null &&
151 firstEvent.tag != "tag:yaml.org,2002:map") {
152 throw new YamlException("Invalid tag for mapping.", firstEvent.span);
153 }
154
155 var children = deepEqualsMap();
156 var node = new YamlMap.internal(
157 children, firstEvent.span, firstEvent.style);
158 _registerAnchor(firstEvent.anchor, node);
159
160 var event = _parser.parse();
161 while (event.type != EventType.MAPPING_END) {
162 var key = _loadNode(event);
163 var value = _loadNode(_parser.parse());
164 children[key] = value;
165 event = _parser.parse();
166 }
167
168 setSpan(node, firstEvent.span.expand(event.span));
169 return node;
170 }
171
172 /// Parses a scalar according to its tag name.
173 YamlScalar _parseByTag(ScalarEvent scalar) {
174 switch (scalar.tag) {
175 case "tag:yaml.org,2002:null": return _parseNull(scalar);
176 case "tag:yaml.org,2002:bool": return _parseBool(scalar);
177 case "tag:yaml.org,2002:int": return _parseInt(scalar);
178 case "tag:yaml.org,2002:float": return _parseFloat(scalar);
179 case "tag:yaml.org,2002:str": return _parseString(scalar);
180 }
181 throw new YamlException('Undefined tag: ${scalar.tag}.', scalar.span);
182 }
183
184 /// Parses a null scalar.
185 YamlScalar _parseNull(ScalarEvent scalar) {
186 // TODO(nweiz): stop using regexps.
187 // TODO(nweiz): add ScalarStyle and implicit metadata to the scalars.
188 if (new RegExp(r"^(null|Null|NULL|~|)$").hasMatch(scalar.value)) {
189 return new YamlScalar.internal(null, scalar.span, scalar.style);
190 } else {
191 return null;
192 }
193 }
194
195 /// Parses a boolean scalar.
196 YamlScalar _parseBool(ScalarEvent scalar) {
197 var match = new RegExp(r"^(?:(true|True|TRUE)|(false|False|FALSE))$").
198 firstMatch(scalar.value);
199 if (match == null) return null;
200 return new YamlScalar.internal(
201 match.group(1) != null, scalar.span, scalar.style);
202 }
203
204 /// Parses an integer scalar.
205 YamlScalar _parseInt(ScalarEvent scalar) {
206 var match = new RegExp(r"^[-+]?[0-9]+$").firstMatch(scalar.value);
207 if (match != null) {
208 return new YamlScalar.internal(
209 int.parse(match.group(0)), scalar.span, scalar.style);
210 }
211
212 match = new RegExp(r"^0o([0-7]+)$").firstMatch(scalar.value);
213 if (match != null) {
214 var n = int.parse(match.group(1), radix: 8);
215 return new YamlScalar.internal(n, scalar.span, scalar.style);
216 }
217
218 match = new RegExp(r"^0x[0-9a-fA-F]+$").firstMatch(scalar.value);
219 if (match != null) {
220 return new YamlScalar.internal(
221 int.parse(match.group(0)), scalar.span, scalar.style);
222 }
223
224 return null;
225 }
226
227 /// Parses a floating-point scalar.
228 YamlScalar _parseFloat(ScalarEvent scalar) {
229 var match = new RegExp(
230 r"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$").
231 firstMatch(scalar.value);
232 if (match != null) {
233 // YAML allows floats of the form "0.", but Dart does not. Fix up those
234 // floats by removing the trailing dot.
235 var matchStr = match.group(0).replaceAll(new RegExp(r"\.$"), "");
236 return new YamlScalar.internal(
237 double.parse(matchStr), scalar.span, scalar.style);
238 }
239
240 match = new RegExp(r"^([+-]?)\.(inf|Inf|INF)$").firstMatch(scalar.value);
241 if (match != null) {
242 var value = match.group(1) == "-" ? -double.INFINITY : double.INFINITY;
243 return new YamlScalar.internal(value, scalar.span, scalar.style);
244 }
245
246 match = new RegExp(r"^\.(nan|NaN|NAN)$").firstMatch(scalar.value);
247 if (match != null) {
248 return new YamlScalar.internal(double.NAN, scalar.span, scalar.style);
249 }
250
251 return null;
252 }
253
254 /// Parses a string scalar.
255 YamlScalar _parseString(ScalarEvent scalar) =>
256 new YamlScalar.internal(scalar.value, scalar.span, scalar.style);
257 }
OLDNEW
« 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