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

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
		if(m_column > 0)
			m_column = 0;

		PopIndentTo(-1);
Jesse Beder's avatar
Jesse Beder committed
29
		ValidateAllSimpleKeys();
30
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)
	{
		PopIndentTo(m_column);
Jesse Beder's avatar
Jesse Beder committed
41
		ValidateAllSimpleKeys();
42
43
44
45
46
47
48
49
50
51
52
		m_simpleKeyAllowed = false;

		// eat
		Eat(3);
		return pToken;
	}

	// DocumentEndToken
	template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken)
	{
		PopIndentTo(-1);
Jesse Beder's avatar
Jesse Beder committed
53
		ValidateAllSimpleKeys();
54
55
56
57
58
59
60
61
62
63
		m_simpleKeyAllowed = false;

		// eat
		Eat(3);
		return pToken;
	}

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

		// eat
		Eat(1);
		return pToken;
	}

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

		// eat
		Eat(1);
		return pToken;
	}

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

		m_flowLevel--;
94
95
96
97
98
99
100
101
102
103
		m_simpleKeyAllowed = false;

		// eat
		Eat(1);
		return pToken;
	}

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

		m_flowLevel--;
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
		m_simpleKeyAllowed = false;

		// eat
		Eat(1);
		return pToken;
	}

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

		// eat
		Eat(1);
		return pToken;
	}

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

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

Jesse Beder's avatar
Jesse Beder committed
136
		PushIndentTo(m_column, true);
137
138
139
140
141
142
143
144
145
146
		m_simpleKeyAllowed = true;

		// eat
		Eat(1);
		return pToken;
	}

	// KeyToken
	template <> KeyToken *Scanner::ScanToken(KeyToken *pToken)
	{
Jesse Beder's avatar
Jesse Beder committed
147
		// handle keys diffently in the block context (and manage indents)
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
		if(m_flowLevel == 0) {
			if(!m_simpleKeyAllowed)
				throw IllegalMapKey();

			PushIndentTo(m_column, false);
		}

		// 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
		Eat(1);
		return pToken;
	}

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

				PushIndentTo(m_column, false);
			}

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

		// eat
		Eat(1);
		return pToken;
	}

Jesse Beder's avatar
Jesse Beder committed
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
	// AnchorToken
	template <> AnchorToken *Scanner::ScanToken(AnchorToken *pToken)
	{
		// insert a potential simple key
		if(m_simpleKeyAllowed)
			InsertSimpleKey();
		m_simpleKeyAllowed = false;

		// eat the indicator
		char indicator = GetChar();
		pToken->alias = (indicator == Keys::Alias);

		// now eat the content
		std::string tag;
		while(Exp::AlphaNumeric.Matches(INPUT))
			tag += GetChar();

		// 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;
	}
223
}