OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// This file contains the node classes for the internal representations of YAML | 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 | 6 /// documents. These nodes are used for both the serialization tree and the |
7 /// representation graph. | 7 /// representation graph. |
8 library yaml.model; | 8 library yaml.model; |
9 | 9 |
| 10 import 'package:source_maps/source_maps.dart'; |
| 11 |
| 12 import 'equality.dart'; |
10 import 'parser.dart'; | 13 import 'parser.dart'; |
11 import 'utils.dart'; | |
12 import 'visitor.dart'; | 14 import 'visitor.dart'; |
13 import 'yaml_exception.dart'; | 15 import 'yaml_exception.dart'; |
14 | 16 |
15 /// The prefix for tag types defined by the YAML spec. | 17 /// The prefix for tag types defined by the YAML spec. |
16 const _YAML_URI_PREFIX = "tag:yaml.org,2002:"; | 18 const _YAML_URI_PREFIX = "tag:yaml.org,2002:"; |
17 | 19 |
18 /// A tag that indicates the type of a YAML node. | 20 /// A tag that indicates the type of a YAML node. |
19 class Tag { | 21 class Tag { |
20 /// The name of the tag, either a URI or a local tag beginning with "!". | 22 /// The name of the tag, either a URI or a local tag beginning with "!". |
21 final String name; | 23 final String name; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 } | 75 } |
74 | 76 |
75 /// The abstract class for YAML nodes. | 77 /// The abstract class for YAML nodes. |
76 abstract class Node { | 78 abstract class Node { |
77 /// Every YAML node has a tag that describes its type. | 79 /// Every YAML node has a tag that describes its type. |
78 Tag tag; | 80 Tag tag; |
79 | 81 |
80 /// Any YAML node can have an anchor associated with it. | 82 /// Any YAML node can have an anchor associated with it. |
81 String anchor; | 83 String anchor; |
82 | 84 |
83 Node(this.tag, [this.anchor]); | 85 /// The source span for this node. |
| 86 Span span; |
| 87 |
| 88 Node(this.tag, this.span, [this.anchor]); |
84 | 89 |
85 bool operator ==(other) { | 90 bool operator ==(other) { |
86 if (other is! Node) return false; | 91 if (other is! Node) return false; |
87 return tag == other.tag; | 92 return tag == other.tag; |
88 } | 93 } |
89 | 94 |
90 int get hashCode => hashCodeFor([tag, anchor]); | 95 int get hashCode => tag.hashCode ^ anchor.hashCode; |
91 | 96 |
92 visit(Visitor v); | 97 visit(Visitor v); |
93 } | 98 } |
94 | 99 |
95 /// A sequence node represents an ordered list of nodes. | 100 /// A sequence node represents an ordered list of nodes. |
96 class SequenceNode extends Node { | 101 class SequenceNode extends Node { |
97 /// The nodes in the sequence. | 102 /// The nodes in the sequence. |
98 List<Node> content; | 103 List<Node> content; |
99 | 104 |
100 SequenceNode(String tagName, this.content) | 105 SequenceNode(String tagName, this.content, Span span) |
101 : super(new Tag.sequence(tagName)); | 106 : super(new Tag.sequence(tagName), span); |
102 | 107 |
103 /// Two sequences are equal if their tags and contents are equal. | 108 /// Two sequences are equal if their tags and contents are equal. |
104 bool operator ==(other) { | 109 bool operator ==(other) { |
105 // Should be super != other; bug 2554 | 110 // Should be super != other; bug 2554 |
106 if (!(super == other) || other is! SequenceNode) return false; | 111 if (!(super == other) || other is! SequenceNode) return false; |
107 if (content.length != other.content.length) return false; | 112 if (content.length != other.content.length) return false; |
108 for (var i = 0; i < content.length; i++) { | 113 for (var i = 0; i < content.length; i++) { |
109 if (content[i] != other.content[i]) return false; | 114 if (content[i] != other.content[i]) return false; |
110 } | 115 } |
111 return true; | 116 return true; |
112 } | 117 } |
113 | 118 |
114 String toString() => '$tag [${content.map((e) => '$e').join(', ')}]'; | 119 String toString() => '$tag [${content.map((e) => '$e').join(', ')}]'; |
115 | 120 |
116 int get hashCode => super.hashCode ^ hashCodeFor(content); | 121 int get hashCode => super.hashCode ^ deepHashCode(content); |
117 | 122 |
118 visit(Visitor v) => v.visitSequence(this); | 123 visit(Visitor v) => v.visitSequence(this); |
119 } | 124 } |
120 | 125 |
121 /// An alias node is a reference to an anchor. | 126 /// An alias node is a reference to an anchor. |
122 class AliasNode extends Node { | 127 class AliasNode extends Node { |
123 AliasNode(String anchor) : super(new Tag.scalar(Tag.yaml("str")), anchor); | 128 AliasNode(String anchor, Span span) |
| 129 : super(new Tag.scalar(Tag.yaml("str")), span, anchor); |
124 | 130 |
125 visit(Visitor v) => v.visitAlias(this); | 131 visit(Visitor v) => v.visitAlias(this); |
126 } | 132 } |
127 | 133 |
128 /// A scalar node represents all YAML nodes that have a single value. | 134 /// A scalar node represents all YAML nodes that have a single value. |
129 class ScalarNode extends Node { | 135 class ScalarNode extends Node { |
130 /// The string value of the scalar node, if it was created by the parser. | 136 /// The string value of the scalar node, if it was created by the parser. |
131 final String _content; | 137 final String _content; |
132 | 138 |
133 /// The Dart value of the scalar node, if it was created by the composer. | 139 /// The Dart value of the scalar node, if it was created by the composer. |
134 final value; | 140 final value; |
135 | 141 |
136 /// Creates a new Scalar node. | 142 /// Creates a new Scalar node. |
137 /// | 143 /// |
138 /// Exactly one of [content] and [value] should be specified. Content should | 144 /// Exactly one of [content] and [value] should be specified. Content should |
139 /// be specified for a newly-parsed scalar that hasn't yet been composed. | 145 /// be specified for a newly-parsed scalar that hasn't yet been composed. |
140 /// Value should be specified for a composed scalar, although `null` is a | 146 /// Value should be specified for a composed scalar, although `null` is a |
141 /// valid value. | 147 /// valid value. |
142 ScalarNode(String tagName, {String content, this.value}) | 148 ScalarNode(String tagName, Span span, {String content, this.value}) |
143 : _content = content, | 149 : _content = content, |
144 super(new Tag.scalar(tagName)); | 150 super(new Tag.scalar(tagName), span); |
145 | 151 |
146 /// Two scalars are equal if their string representations are equal. | 152 /// Two scalars are equal if their string representations are equal. |
147 bool operator ==(other) { | 153 bool operator ==(other) { |
148 // Should be super != other; bug 2554 | 154 // Should be super != other; bug 2554 |
149 if (!(super == other) || other is! ScalarNode) return false; | 155 if (!(super == other) || other is! ScalarNode) return false; |
150 return content == other.content; | 156 return content == other.content; |
151 } | 157 } |
152 | 158 |
153 /// Returns the string representation of the scalar. After composition, this | 159 /// Returns the string representation of the scalar. After composition, this |
154 /// is equal to the canonical serialization of the value of the scalar. | 160 /// is equal to the canonical serialization of the value of the scalar. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 int get hashCode => super.hashCode ^ content.hashCode; | 224 int get hashCode => super.hashCode ^ content.hashCode; |
219 | 225 |
220 visit(Visitor v) => v.visitScalar(this); | 226 visit(Visitor v) => v.visitScalar(this); |
221 } | 227 } |
222 | 228 |
223 /// A mapping node represents an unordered map of nodes to nodes. | 229 /// A mapping node represents an unordered map of nodes to nodes. |
224 class MappingNode extends Node { | 230 class MappingNode extends Node { |
225 /// The node map. | 231 /// The node map. |
226 Map<Node, Node> content; | 232 Map<Node, Node> content; |
227 | 233 |
228 MappingNode(String tagName, this.content) | 234 MappingNode(String tagName, this.content, Span span) |
229 : super(new Tag.mapping(tagName)); | 235 : super(new Tag.mapping(tagName), span); |
230 | 236 |
231 /// Two mappings are equal if their tags and contents are equal. | 237 /// Two mappings are equal if their tags and contents are equal. |
232 bool operator ==(other) { | 238 bool operator ==(other) { |
233 // Should be super != other; bug 2554 | 239 // Should be super != other; bug 2554 |
234 if (!(super == other) || other is! MappingNode) return false; | 240 if (!(super == other) || other is! MappingNode) return false; |
235 if (content.length != other.content.length) return false; | 241 if (content.length != other.content.length) return false; |
236 for (var key in content.keys) { | 242 for (var key in content.keys) { |
237 if (!other.content.containsKey(key)) return false; | 243 if (!other.content.containsKey(key)) return false; |
238 if (content[key] != other.content[key]) return false; | 244 if (content[key] != other.content[key]) return false; |
239 } | 245 } |
240 return true; | 246 return true; |
241 } | 247 } |
242 | 248 |
243 String toString() { | 249 String toString() { |
244 var strContent = content.keys | 250 var strContent = content.keys |
245 .map((k) => '${k}: ${content[k]}') | 251 .map((k) => '${k}: ${content[k]}') |
246 .join(', '); | 252 .join(', '); |
247 return '$tag {$strContent}'; | 253 return '$tag {$strContent}'; |
248 } | 254 } |
249 | 255 |
250 int get hashCode => super.hashCode ^ hashCodeFor(content); | 256 int get hashCode => super.hashCode ^ deepHashCode(content); |
251 | 257 |
252 visit(Visitor v) => v.visitMapping(this); | 258 visit(Visitor v) => v.visitMapping(this); |
253 } | 259 } |
OLD | NEW |