scantoken.cpp 4.67 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
#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
25
26
		if(INPUT.column > 0)
			INPUT.column = 0;
27
28

		PopIndentTo(-1);
Jesse Beder's avatar
Jesse Beder committed
29
		ValidateAllSimpleKeys();
30
31
32
33
34
35
36
37
38
39

		m_simpleKeyAllowed = false;
		m_endedStream = true;

		return pToken;
	}

	// DocumentStartToken
	template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken)
	{
40
		PopIndentTo(INPUT.column);
Jesse Beder's avatar
Jesse Beder committed
41
		ValidateAllSimpleKeys();
42
43
44
		m_simpleKeyAllowed = false;

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

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

		// eat
57
		INPUT.Eat(3);
58
59
60
61
62
63
		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
		m_simpleKeyAllowed = true;

		// eat
70
		INPUT.Eat(1);
71
72
73
74
75
76
		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
		m_simpleKeyAllowed = true;

		// eat
83
		INPUT.Eat(1);
84
85
86
87
88
89
		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
		m_simpleKeyAllowed = false;

		// eat
97
		INPUT.Eat(1);
98
99
100
101
102
103
		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
		m_simpleKeyAllowed = false;

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

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

		// eat
121
		INPUT.Eat(1);
122
123
124
125
126
127
128
		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

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

		// eat
140
		INPUT.Eat(1);
141
142
143
144
145
146
		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
		if(m_flowLevel == 0) {
			if(!m_simpleKeyAllowed)
				throw IllegalMapKey();

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

		// 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
162
		INPUT.Eat(1);
163
164
165
166
167
168
		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
			if(m_flowLevel == 0) {
				if(!m_simpleKeyAllowed)
					throw IllegalMapValue();

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

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

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

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

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

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

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