scantoken.cpp 8.23 KB
Newer Older
1
2
3
4
#include "scanner.h"
#include "token.h"
#include "exceptions.h"
#include "exp.h"
5
#include "scanscalar.h"
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

namespace YAML
{
	///////////////////////////////////////////////////////////////////////
	// Specialization for scanning specific tokens

	// StreamStartToken
	template <> StreamStartToken *Scanner::ScanToken(StreamStartToken *pToken)
	{
		m_startedStream = true;
		m_simpleKeyAllowed = true;
		m_indents.push(-1);

		return pToken;
	}

	// StreamEndToken
	template <> StreamEndToken *Scanner::ScanToken(StreamEndToken *pToken)
	{
		// force newline
26
27
		if(INPUT.column > 0)
			INPUT.column = 0;
28
29

		PopIndentTo(-1);
30
		VerifyAllSimpleKeys();
31
32
33
34
35
36
37
38
39
40

		m_simpleKeyAllowed = false;
		m_endedStream = true;

		return pToken;
	}

	// DocumentStartToken
	template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken)
	{
41
		PopIndentTo(INPUT.column);
42
		VerifyAllSimpleKeys();
43
44
45
		m_simpleKeyAllowed = false;

		// eat
46
		INPUT.Eat(3);
47
48
49
50
51
52
53
		return pToken;
	}

	// DocumentEndToken
	template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken)
	{
		PopIndentTo(-1);
54
		VerifyAllSimpleKeys();
55
56
57
		m_simpleKeyAllowed = false;

		// eat
58
		INPUT.Eat(3);
59
60
61
62
63
64
		return pToken;
	}

	// FlowSeqStartToken
	template <> FlowSeqStartToken *Scanner::ScanToken(FlowSeqStartToken *pToken)
	{
Jesse Beder's avatar
Jesse Beder committed
65
66
		// flow sequences can be simple keys
		InsertSimpleKey();
Jesse Beder's avatar
Jesse Beder committed
67
		m_flowLevel++;
68
69
70
		m_simpleKeyAllowed = true;

		// eat
71
		INPUT.Eat(1);
72
73
74
75
76
77
		return pToken;
	}

	// FlowMapStartToken
	template <> FlowMapStartToken *Scanner::ScanToken(FlowMapStartToken *pToken)
	{
Jesse Beder's avatar
Jesse Beder committed
78
79
		// flow maps can be simple keys
		InsertSimpleKey();
Jesse Beder's avatar
Jesse Beder committed
80
		m_flowLevel++;
81
82
83
		m_simpleKeyAllowed = true;

		// eat
84
		INPUT.Eat(1);
85
86
87
88
89
90
		return pToken;
	}

	// FlowSeqEndToken
	template <> FlowSeqEndToken *Scanner::ScanToken(FlowSeqEndToken *pToken)
	{
Jesse Beder's avatar
Jesse Beder committed
91
92
93
94
		if(m_flowLevel == 0)
			throw IllegalFlowEnd();

		m_flowLevel--;
95
96
97
		m_simpleKeyAllowed = false;

		// eat
98
		INPUT.Eat(1);
99
100
101
102
103
104
		return pToken;
	}

	// FlowMapEndToken
	template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken)
	{
Jesse Beder's avatar
Jesse Beder committed
105
106
107
108
		if(m_flowLevel == 0)
			throw IllegalFlowEnd();

		m_flowLevel--;
109
110
111
		m_simpleKeyAllowed = false;

		// eat
112
		INPUT.Eat(1);
113
114
115
116
117
118
119
120
121
		return pToken;
	}

	// FlowEntryToken
	template <> FlowEntryToken *Scanner::ScanToken(FlowEntryToken *pToken)
	{
		m_simpleKeyAllowed = true;

		// eat
122
		INPUT.Eat(1);
123
124
125
126
127
128
129
		return pToken;
	}

	// BlockEntryToken
	template <> BlockEntryToken *Scanner::ScanToken(BlockEntryToken *pToken)
	{
		// we better be in the block context!
Jesse Beder's avatar
Jesse Beder committed
130
131
		if(m_flowLevel > 0)
			throw IllegalBlockEntry();
132

Jesse Beder's avatar
Jesse Beder committed
133
134
135
		// can we put it here?
		if(!m_simpleKeyAllowed)
			throw IllegalBlockEntry();
136

137
		PushIndentTo(INPUT.column, true);
138
139
140
		m_simpleKeyAllowed = true;

		// eat
141
		INPUT.Eat(1);
142
143
144
145
146
147
		return pToken;
	}

	// KeyToken
	template <> KeyToken *Scanner::ScanToken(KeyToken *pToken)
	{
Jesse Beder's avatar
Jesse Beder committed
148
		// handle keys diffently in the block context (and manage indents)
149
150
151
152
		if(m_flowLevel == 0) {
			if(!m_simpleKeyAllowed)
				throw IllegalMapKey();

153
			PushIndentTo(INPUT.column, false);
154
155
156
157
158
159
160
161
162
		}

		// can only put a simple key here if we're in block context
		if(m_flowLevel == 0)
			m_simpleKeyAllowed = true;
		else
			m_simpleKeyAllowed = false;

		// eat
163
		INPUT.Eat(1);
164
165
166
167
168
169
		return pToken;
	}

	// ValueToken
	template <> ValueToken *Scanner::ScanToken(ValueToken *pToken)
	{
Jesse Beder's avatar
Jesse Beder committed
170
		// does this follow a simple key?
171
		if(m_isLastKeyValid) {
Jesse Beder's avatar
Jesse Beder committed
172
173
			// can't follow a simple key with another simple key (dunno why, though - it seems fine)
			m_simpleKeyAllowed = false;
174
		} else {
Jesse Beder's avatar
Jesse Beder committed
175
			// handle values diffently in the block context (and manage indents)
176
177
178
179
			if(m_flowLevel == 0) {
				if(!m_simpleKeyAllowed)
					throw IllegalMapValue();

180
				PushIndentTo(INPUT.column, false);
181
182
			}

Jesse Beder's avatar
Jesse Beder committed
183
184
185
186
187
188
			// can only put a simple key here if we're in block context
			if(m_flowLevel == 0)
				m_simpleKeyAllowed = true;
			else
				m_simpleKeyAllowed = false;
		}
189
190

		// eat
191
		INPUT.Eat(1);
192
193
194
		return pToken;
	}

Jesse Beder's avatar
Jesse Beder committed
195
196
197
198
199
200
201
202
203
	// AnchorToken
	template <> AnchorToken *Scanner::ScanToken(AnchorToken *pToken)
	{
		// insert a potential simple key
		if(m_simpleKeyAllowed)
			InsertSimpleKey();
		m_simpleKeyAllowed = false;

		// eat the indicator
204
		char indicator = INPUT.GetChar();
Jesse Beder's avatar
Jesse Beder committed
205
206
207
208
209
		pToken->alias = (indicator == Keys::Alias);

		// now eat the content
		std::string tag;
		while(Exp::AlphaNumeric.Matches(INPUT))
210
			tag += INPUT.GetChar();
Jesse Beder's avatar
Jesse Beder committed
211
212
213
214
215
216
217
218
219
220
221
222
223

		// we need to have read SOMETHING!
		if(tag.empty())
			throw AnchorNotFound();

		// and needs to end correctly
		if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT))
			throw IllegalCharacterInAnchor();

		// and we're done
		pToken->value = tag;
		return pToken;
	}
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343

	// PlainScalarToken
	template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken)
	{
		// set up the scanning parameters
		ScanScalarParams params;
		params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment);
		params.eatEnd = false;
		params.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1);
		params.fold = true;
		params.eatLeadingWhitespace = true;
		params.trimTrailingSpaces = true;
		params.chomp = CLIP;
		params.onDocIndicator = BREAK;
		params.onTabInIndentation = THROW;

		// insert a potential simple key
		if(m_simpleKeyAllowed)
			InsertSimpleKey();

		pToken->value = ScanScalar(INPUT, params);

		// can have a simple key only if we ended the scalar by starting a new line
		m_simpleKeyAllowed = params.leadingSpaces;

		// finally, we can't have any colons in a scalar, so if we ended on a colon, there
		// had better be a break after it
		if(Exp::IllegalColonInScalar.Matches(INPUT))
			throw IllegalScalar();

		return pToken;
	}

	// QuotedScalarToken
	template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken)
	{
		// eat single or double quote
		char quote = INPUT.GetChar();
		pToken->single = (quote == '\'');

		// setup the scanning parameters
		ScanScalarParams params;
		params.end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote));
		params.eatEnd = true;
		params.escape = (pToken->single ? '\'' : '\\');
		params.indent = 0;
		params.fold = true;
		params.eatLeadingWhitespace = true;
		params.trimTrailingSpaces = false;
		params.chomp = CLIP;
		params.onDocIndicator = THROW;

		// insert a potential simple key
		if(m_simpleKeyAllowed)
			InsertSimpleKey();

		pToken->value = ScanScalar(INPUT, params);
		m_simpleKeyAllowed = false;

		return pToken;
	}

	// BlockScalarToken
	// . These need a little extra processing beforehand.
	// . We need to scan the line where the indicator is (this doesn't count as part of the scalar),
	//   and then we need to figure out what level of indentation we'll be using.
	template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken)
	{
		ScanScalarParams params;
		params.indent = 1;
		params.detectIndent = true;

		// eat block indicator ('|' or '>')
		char indicator = INPUT.GetChar();
		params.fold = (indicator == Keys::FoldedScalar);

		// eat chomping/indentation indicators
		int n = Exp::Chomp.Match(INPUT);
		for(int i=0;i<n;i++) {
			char ch = INPUT.GetChar();
			if(ch == '+')
				params.chomp = KEEP;
			else if(ch == '-')
				params.chomp = STRIP;
			else if(Exp::Digit.Matches(ch)) {
				if(ch == '0')
					throw ZeroIndentationInBlockScalar();

				params.indent = ch - '0';
				params.detectIndent = false;
			}
		}

		// now eat whitespace
		while(Exp::Blank.Matches(INPUT))
			INPUT.Eat(1);

		// and comments to the end of the line
		if(Exp::Comment.Matches(INPUT))
			while(INPUT && !Exp::Break.Matches(INPUT))
				INPUT.Eat(1);

		// if it's not a line break, then we ran into a bad character inline
		if(INPUT && !Exp::Break.Matches(INPUT))
			throw UnexpectedCharacterInBlockScalar();

		// set the initial indentation
		if(m_indents.top() >= 0)
			params.indent += m_indents.top();

		params.eatLeadingWhitespace = false;
		params.trimTrailingSpaces = false;
		params.onTabInIndentation = THROW;

		pToken->value = ScanScalar(INPUT, params);

		// simple keys always ok after block scalars (since we're gonna start a new line anyways)
		m_simpleKeyAllowed = true;
		return pToken;
	}
344
}