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