1 
2 //          Copyright Ferdinand Majerech 2011.
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          http://www.boost.org/LICENSE_1_0.txt)
6 
7 /**
8  * YAML events.
9  * Code based on PyYAML: http://www.pyyaml.org
10  */
11 module dyaml.event;
12 
13 import std.array;
14 import std.conv;
15 
16 import dyaml.exception;
17 import dyaml.reader;
18 import dyaml.tagdirective;
19 import dyaml.style;
20 
21 
22 package:
23 ///Event types.
24 enum EventID : ubyte
25 {
26     Invalid = 0,     /// Invalid (uninitialized) event.
27     StreamStart,     /// Stream start
28     StreamEnd,       /// Stream end
29     DocumentStart,   /// Document start
30     DocumentEnd,     /// Document end
31     Alias,           /// Alias
32     Scalar,          /// Scalar
33     SequenceStart,   /// Sequence start
34     SequenceEnd,     /// Sequence end
35     MappingStart,    /// Mapping start
36     MappingEnd       /// Mapping end
37 }
38 
39 /**
40  * YAML event produced by parser.
41  *
42  * 48 bytes on 64bit.
43  */
44 struct Event
45 {
46     @disable int opCmp(ref Event);
47 
48     ///Value of the event, if any.
49     string value;
50     ///Start position of the event in file/stream.
51     Mark startMark;
52     ///End position of the event in file/stream.
53     Mark endMark;
54     union
55     {
56         struct
57         {
58             ///Anchor of the event, if any.
59             string _anchor;
60             ///Tag of the event, if any.
61             string _tag;
62         }
63         ///Tag directives, if this is a DocumentStart.
64         //TagDirectives tagDirectives;
65         TagDirective[] _tagDirectives;
66     }
67     ///Event type.
68     EventID id = EventID.Invalid;
69     ///Style of scalar event, if this is a scalar event.
70     ScalarStyle scalarStyle = ScalarStyle.Invalid;
71     union
72     {
73         ///Should the tag be implicitly resolved?
74         bool implicit;
75         /**
76          * Is this document event explicit?
77          *
78          * Used if this is a DocumentStart or DocumentEnd.
79          */
80         bool explicitDocument;
81     }
82     ///Collection style, if this is a SequenceStart or MappingStart.
83     CollectionStyle collectionStyle = CollectionStyle.Invalid;
84 
85     ///Is this a null (uninitialized) event?
86     @property bool isNull() const pure @safe nothrow {return id == EventID.Invalid;}
87 
88     ///Get string representation of the token ID.
89     @property string idString() const @safe {return to!string(id);}
90 
91     auto ref anchor() inout @trusted pure {
92         assert(id != EventID.DocumentStart, "DocumentStart events cannot have anchors.");
93         return _anchor;
94     }
95 
96     auto ref tag() inout @trusted pure {
97         assert(id != EventID.DocumentStart, "DocumentStart events cannot have tags.");
98         return _tag;
99     }
100 
101     auto ref tagDirectives() inout @trusted pure {
102         assert(id == EventID.DocumentStart, "Only DocumentStart events have tag directives.");
103         return _tagDirectives;
104     }
105 
106     static assert(Event.sizeof <= 64, "Event struct larger than expected");
107 }
108 
109 /**
110  * Construct a simple event.
111  *
112  * Params:  start    = Start position of the event in the file/stream.
113  *          end      = End position of the event in the file/stream.
114  *          anchor   = Anchor, if this is an alias event.
115  */
116 Event event(EventID id)(const Mark start, const Mark end, const string anchor = null)
117     @safe
118 {
119     Event result;
120     result.startMark = start;
121     result.endMark   = end;
122     result.anchor    = anchor;
123     result.id        = id;
124     return result;
125 }
126 
127 /**
128  * Construct a collection (mapping or sequence) start event.
129  *
130  * Params:  start    = Start position of the event in the file/stream.
131  *          end      = End position of the event in the file/stream.
132  *          anchor   = Anchor of the sequence, if any.
133  *          tag      = Tag of the sequence, if specified.
134  *          implicit = Should the tag be implicitly resolved?
135  *          style = Style to use when outputting document.
136  */
137 Event collectionStartEvent(EventID id)
138     (const Mark start, const Mark end, const string anchor, const string tag,
139      const bool implicit, const CollectionStyle style) pure @safe nothrow
140 {
141     static assert(id == EventID.SequenceStart || id == EventID.SequenceEnd ||
142                   id == EventID.MappingStart || id == EventID.MappingEnd);
143     Event result;
144     result.startMark       = start;
145     result.endMark         = end;
146     result.anchor          = anchor;
147     result.tag             = tag;
148     result.id              = id;
149     result.implicit        = implicit;
150     result.collectionStyle = style;
151     return result;
152 }
153 
154 /**
155  * Construct a stream start event.
156  *
157  * Params:  start    = Start position of the event in the file/stream.
158  *          end      = End position of the event in the file/stream.
159  */
160 Event streamStartEvent(const Mark start, const Mark end)
161     pure @safe nothrow
162 {
163     Event result;
164     result.startMark = start;
165     result.endMark   = end;
166     result.id        = EventID.StreamStart;
167     return result;
168 }
169 
170 ///Aliases for simple events.
171 alias streamEndEvent = event!(EventID.StreamEnd);
172 alias aliasEvent = event!(EventID.Alias);
173 alias sequenceEndEvent = event!(EventID.SequenceEnd);
174 alias mappingEndEvent = event!(EventID.MappingEnd);
175 
176 ///Aliases for collection start events.
177 alias sequenceStartEvent = collectionStartEvent!(EventID.SequenceStart);
178 alias mappingStartEvent = collectionStartEvent!(EventID.MappingStart);
179 
180 /**
181  * Construct a document start event.
182  *
183  * Params:  start         = Start position of the event in the file/stream.
184  *          end           = End position of the event in the file/stream.
185  *          explicit      = Is this an explicit document start?
186  *          YAMLVersion   = YAML version string of the document.
187  *          tagDirectives = Tag directives of the document.
188  */
189 Event documentStartEvent(const Mark start, const Mark end, const bool explicit, string YAMLVersion,
190                          TagDirective[] tagDirectives) pure @safe nothrow
191 {
192     Event result;
193     result.value            = YAMLVersion;
194     result.startMark        = start;
195     result.endMark          = end;
196     result.id               = EventID.DocumentStart;
197     result.explicitDocument = explicit;
198     result.tagDirectives    = tagDirectives;
199     return result;
200 }
201 
202 /**
203  * Construct a document end event.
204  *
205  * Params:  start    = Start position of the event in the file/stream.
206  *          end      = End position of the event in the file/stream.
207  *          explicit = Is this an explicit document end?
208  */
209 Event documentEndEvent(const Mark start, const Mark end, const bool explicit) pure @safe nothrow
210 {
211     Event result;
212     result.startMark        = start;
213     result.endMark          = end;
214     result.id               = EventID.DocumentEnd;
215     result.explicitDocument = explicit;
216     return result;
217 }
218 
219 /// Construct a scalar event.
220 ///
221 /// Params:  start    = Start position of the event in the file/stream.
222 ///          end      = End position of the event in the file/stream.
223 ///          anchor   = Anchor of the scalar, if any.
224 ///          tag      = Tag of the scalar, if specified.
225 ///          implicit = Should the tag be implicitly resolved?
226 ///          value    = String value of the scalar.
227 ///          style    = Scalar style.
228 Event scalarEvent(const Mark start, const Mark end, const string anchor, const string tag,
229                   const bool implicit, const string value,
230                   const ScalarStyle style = ScalarStyle.Invalid) @safe pure nothrow @nogc
231 {
232     Event result;
233     result.value       = value;
234     result.startMark   = start;
235     result.endMark     = end;
236 
237     result.anchor  = anchor;
238     result.tag     = tag;
239 
240     result.id          = EventID.Scalar;
241     result.scalarStyle = style;
242     result.implicit    = implicit;
243     return result;
244 }