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

Side by Side Diff: lib/yaml/model.dart

Issue 10153004: Add a basic YAML processor. Much of the language is still unimplemented. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 8 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 // This file contains the node classes for the internal representations of YAML
6 // documents. These nodes are used for both the serialization tree and the
7 // representation graph.
8
9 /** A tag that indicates the type of a YAML node. */
10 class _Tag implements Hashable {
11 // TODO(nweiz): it would better match the semantics of the spec if there were
12 // a singleton instance of this class for each tag.
13
14 static final SCALAR_KIND = 0;
15 static final SEQUENCE_KIND = 1;
16 static final MAPPING_KIND = 2;
17
18 /** The name of the tag, either a URI or a local tag beginning with "!". */
19 final String name;
20
21 /** The kind of the tag: SCALAR_KIND, SEQUENCE_KIND, or MAPPING_KIND. */
22 final int kind;
23
24 _Tag(String this.name, int this.kind);
25
26 _Tag.scalar(String name) : this(name, SCALAR_KIND);
27 _Tag.sequence(String name) : this(name, SEQUENCE_KIND);
28 _Tag.mapping(String name) : this(name, MAPPING_KIND);
Bob Nystrom 2012/04/20 20:28:55 These are nice.
29
30 /** Returns the standard YAML tag URI for [type]. */
31 static String yaml(String type) => "tag:yaml.org,2002:$type";
32
33 /** Two tags are equal if their URIs are equal. */
34 operator ==(var other) {
Bob Nystrom 2012/04/20 20:28:55 No "var" here.
nweiz 2012/04/23 23:06:33 Done.
35 if (other is! _Tag) return false;
36 _Tag otherTag = other;
Bob Nystrom 2012/04/20 20:28:55 Unused var.
nweiz 2012/04/23 23:06:33 Done.
37 return name == other.name;
38 }
39
40 String toString() {
41 if (name.startsWith('tag:yaml.org,2002:')) {
Bob Nystrom 2012/04/20 20:28:55 Pull this string out into a constant?
nweiz 2012/04/23 23:06:33 Done.
42 return '!!${name.substring('tag:yaml.org,2002:'.length)}';
43 } else {
44 return '!<$name>';
45 }
46 }
47
48 int hashCode() => name.hashCode();
49 }
50
51 /** The abstract class for YAML nodes. */
52 class _Node implements Hashable {
53 /** Every YAML node has a tag that describes its type. */
54 _Tag tag;
55
56 /** Any YAML node can have an anchor associated with it. */
57 String anchor;
58
59 _Node(_Tag this.tag, [String this.anchor]);
Bob Nystrom 2012/04/20 20:28:55 Don't need types for "this." params. Here and else
nweiz 2012/04/23 23:06:33 Done.
60
61 bool operator ==(var other) {
Bob Nystrom 2012/04/20 20:28:55 Remove "var" here and elsewhere.
nweiz 2012/04/23 23:06:33 Done.
62 if (other is! _Node) return false;
63 _Node otherNode = other;
Bob Nystrom 2012/04/20 20:28:55 You can ditch this and be consistent with _Tag.
nweiz 2012/04/23 23:06:33 Done.
64 return tag == otherNode.tag;
65 }
66
67 int hashCode() => _hashCode([tag, anchor]);
68
69 abstract visit(_Visitor v);
70 }
71
72 /** A sequence node represents an ordered list of nodes. */
73 class _SequenceNode extends _Node {
74 /** The nodes in the sequence. */
75 List<_Node> content;
76
77 _SequenceNode(String tagName, List<_Node> this.content)
78 : super(new _Tag.sequence(tagName));
79
80 /** Two sequences are equal if their tags and contents are equal. */
81 bool operator ==(var other) {
82 // Should be super != other; bug 2554
83 if (!(super == other) || other is! _SequenceNode) return false;
84 _SequenceNode otherSeq = other;
85 if (content.length != otherSeq.content.length) return false;
86 for (var i = 0; i < content.length; i++) {
87 if (content[i] != otherSeq.content[i]) return false;
88 }
89 return true;
90 }
91
92 String toString() => '$tag [${Strings.join(content.map((e) => '$e'), ', ')}]';
Bob Nystrom 2012/04/20 20:28:55 This map here is weird. Seems silly that Strings.j
nweiz 2012/04/23 23:06:33 Bug 2690 filed.
93
94 int hashCode() => super.hashCode() ^ _hashCode(content);
95
96 visit(_Visitor v) => v.visitSequence(this);
97 }
98
99 /** An alias node is a reference to an anchor. */
100 class _AliasNode extends _Node {
101 _AliasNode(String anchor) : super(new _Tag.scalar(_Tag.yaml("str")), anchor);
Bob Nystrom 2012/04/20 20:28:55 Why "str" here?
nweiz 2012/04/23 23:06:33 I needed something. The spec isn't clear on what t
102
103 visit(_Visitor v) => v.visitAlias(this);
104 }
105
106 /** A scalar node represents all YAML nodes that have a single value. */
107 class _ScalarNode extends _Node {
108 /** The string value of the scalar node, if it was created by the parser. */
109 final String _content;
110
111 /** The Dart value of the scalar node, if it was created by the composer. */
112 final value;
113
114 /**
115 * Creates a new Scalar node.
116 *
117 * Exactly one of [content] and [value] should be specified. Content should be
118 * specified for a newly-parsed scalar that hasn't yet been composed. Value
119 * should be specified for a composed scalar, although `null` is a valid
120 * value.
121 */
122 _ScalarNode(String tagName, [String content, this.value])
123 : _content = content,
124 super(new _Tag.scalar(tagName));
125
126 /** Two scalars are equal if their string representations are equal. */
127 bool operator ==(var other) {
128 // Should be super != other; bug 2554
129 if (!(super == other) || other is! _ScalarNode) return false;
130 _ScalarNode otherScalar = other;
131 return content == other.content;
132 }
133
134 /**
135 * Returns the string representation of the scalar. After composition, this is
136 * equal to the canonical serialization of the value of the scalar.
137 */
138 String get content() => _content != null ? _content : canonicalContent;
139
140 /**
141 * Returns the canonical serialization of the value of the scalar. If the
142 * value isn't given, the result of this will be "null".
143 */
144 String get canonicalContent() {
145 if (value == null || value is bool || value is int) return '$value';
146
147 if (value is num) {
148 // 20 is the maximum value for this argument, which we use since YAML
149 // doesn't specify a maximum.
150 return value.toStringAsExponential(20).
151 replaceFirst(const RegExp("0+e"), "e");
152 }
153
154 if (value is String) {
155 var escapedValue = value.charCodes().map((c) {
Bob Nystrom 2012/04/20 20:28:55 For the common case where the string doesn't conta
nweiz 2012/04/23 23:06:33 Done.
156 switch (c) {
157 case _Parser.TAB: return "\\t";
158 case _Parser.LF: return "\\n";
159 case _Parser.CR: return "\\r";
160 case _Parser.DOUBLE_QUOTE: return '\\"';
161 case _Parser.NULL: return "\\0";
162 case _Parser.BELL: return "\\a";
163 case _Parser.BACKSPACE: return "\\b";
164 case _Parser.VERTICAL_TAB: return "\\v";
165 case _Parser.FORM_FEED: return "\\f";
166 case _Parser.ESCAPE: return "\\e";
167 case _Parser.BACKSLASH: return "\\\\";
168 case _Parser.NEL: return "\\N";
169 case _Parser.NBSP: return "\\_";
170 case _Parser.LINE_SEPARATOR: return "\\L";
171 case _Parser.PARAGRAPH_SEPARATOR: return "\\P";
172 default:
173 if (c < 0x20 || (c >= 0x7f && c < 0x100)) {
174 return "\\x${_pad(c.toRadixString(16).toUpperCase(), 2)}";
175 } else if (c >= 0x100 && c < 0x10000) {
176 return "\\u${_pad(c.toRadixString(16).toUpperCase(), 4)}";
177 } else if (c >= 0x10000) {
178 return "\\u${_pad(c.toRadixString(16).toUpperCase(), 8)}";
179 } else {
180 return new String.fromCharCodes([c]);
181 }
182 }
183 });
184 return '"${Strings.join(escapedValue, '')}"';
185 }
186
187 throw new Error("unknown scalar value: $value");
188 }
189
190 String toString() {
Bob Nystrom 2012/04/20 20:28:55 =>
nweiz 2012/04/23 23:06:33 Done.
191 return '$tag "$content"';
192 }
193
194 /**
195 * Left-pads [str] with zeros so that it's at least [length] characters
196 * long.
197 */
198 String _pad(String str, int length) {
Bob Nystrom 2012/04/20 20:28:55 "_zeroPad"?
nweiz 2012/04/23 23:06:33 Done.
199 assert(length >= str.length);
200 var prefix = new List();
Bob Nystrom 2012/04/20 20:28:55 new List() -> []
nweiz 2012/04/23 23:06:33 Done.
201 prefix.insertRange(0, length - str.length, '0');
Bob Nystrom 2012/04/20 20:28:55 Clever!
nweiz 2012/04/23 23:06:33 I'd rather write '0' * (length - str.length), but
202 return '${Strings.join(prefix, '')}$str';
203 }
204
205 int hashCode() => super.hashCode() ^ content.hashCode();
206
207 visit(_Visitor v) => v.visitScalar(this);
208 }
209
210 /** A mapping node represents an unordered map of nodes to nodes. */
211 class _MappingNode extends _Node {
212 /** The node map. */
213 Map<_Node, _Node> content;
214
215 _MappingNode(String tagName, Map<_Node, _Node> this.content)
216 : super(new _Tag.mapping(tagName));
217
218 /** Two mappings are equal if their tags and contents are equal. */
219 bool operator ==(var other) {
220 // Should be super != other; bug 2554
221 if (!(super == other) || other is! _MappingNode) return false;
222 _MappingNode otherMap = other;
223 if (content.length != otherMap.content.length) return false;
224 for (var key in content.getKeys()) {
225 if (!otherMap.content.containsKey(key)) return false;
226 if (content[key] != otherMap.content[key]) return false;
227 }
228 return true;
229 }
230
231 String toString() {
232 var strContent = Strings.join(content.getKeys().
233 map((k) => '${k}: ${content[k]}'), ', ');
234 return '$tag {$strContent}';
235 }
236
237 int hashCode() => super.hashCode() ^ _hashCode(content);
238
239 visit(_Visitor v) => v.visitMapping(this);
240 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698