"include/vscode:/vscode.git/clone" did not exist on "b456d5e53ec59c9fe90ee68a6b1c575934fb508d"
scanner.cpp 6.52 KB
Newer Older
beder's avatar
beder committed
1
2
#include "scanner.h"
#include "token.h"
beder's avatar
beder committed
3
#include "exceptions.h"
4
#include "exp.h"
beder's avatar
beder committed
5
6
7
8

namespace YAML
{
	Scanner::Scanner(std::istream& in)
9
		: INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0)
beder's avatar
beder committed
10
11
12
13
14
	{
	}

	Scanner::~Scanner()
	{
beder's avatar
beder committed
15
16
17
18
		while(!m_tokens.empty()) {
			delete m_tokens.front();
			m_tokens.pop();
		}
beder's avatar
beder committed
19
20
	}

21
22
23
24
25
26
27
28
29
	// GetNextToken
	// . Removes and returns the next token on the queue.
	Token *Scanner::GetNextToken()
	{
		Token *pToken = PeekNextToken();
		if(!m_tokens.empty())
			m_tokens.pop();
		return pToken;
	}
beder's avatar
beder committed
30

31
32
33
34
35
36
37
38
39
40
41
42
43
44
	// PopNextToken
	// . Simply removes the next token on the queue.
	void Scanner::PopNextToken()
	{
		GetNextToken();
	}

	// EatNextToken
	// . Removes and deletes the next token on the queue
	void Scanner::EatNextToken()
	{
		delete GetNextToken();
	}

45
46
47
	// PeekNextToken
	// . Returns (but does not remove) the next token on the queue, and scans if only we need to.
	Token *Scanner::PeekNextToken()
beder's avatar
beder committed
48
	{
49
50
		while(1) {
			Token *pToken = 0;
beder's avatar
beder committed
51

52
53
54
			// is there a token in the queue?
			if(!m_tokens.empty())
				pToken = m_tokens.front();
beder's avatar
beder committed
55

56
57
58
59
60
61
			// (here's where we clean up the impossible tokens)
			if(pToken && pToken->status == TS_INVALID) {
				m_tokens.pop();
				delete pToken;
				continue;
			}
beder's avatar
beder committed
62

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
			// on unverified tokens, we just have to wait
			if(pToken && pToken->status == TS_UNVERIFIED)
				pToken = 0;

			// then that's what we want
			if(pToken)
				return pToken;

			// no token? maybe we've actually finished
			if(m_endedStream)
				break;

			// no? then scan...
			ScanNextToken();
		}

		return 0;
beder's avatar
beder committed
80
81
	}

beder's avatar
beder committed
82
83
84
	// ScanNextToken
	// . The main scanning function; here we branch out and
	//   scan whatever the next token should be.
beder's avatar
beder committed
85
	void Scanner::ScanNextToken()
beder's avatar
beder committed
86
	{
87
88
89
		if(m_endedStream)
			return;

beder's avatar
beder committed
90
		if(!m_startedStream)
91
			return StartStream();
beder's avatar
beder committed
92

beder's avatar
beder committed
93
		// get rid of whitespace, etc. (in between tokens it should be irrelevent)
beder's avatar
beder committed
94
		ScanToNextToken();
beder's avatar
beder committed
95
96

		// check the latest simple key
97
		VerifySimpleKey();
beder's avatar
beder committed
98
99

		// maybe need to end some blocks
100
		PopIndentTo(INPUT.column);
beder's avatar
beder committed
101

beder's avatar
beder committed
102
103
104
105
106
		// *****
		// And now branch based on the next few characters!
		// *****

		// end of stream
beder's avatar
beder committed
107
		if(INPUT.peek() == EOF)
108
			return EndStream();
beder's avatar
beder committed
109

beder's avatar
beder committed
110
		if(INPUT.column == 0 && INPUT.peek() == Keys::Directive)
111
			return ScanDirective();
beder's avatar
beder committed
112

beder's avatar
beder committed
113
		// document token
beder's avatar
beder committed
114
		if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT))
115
			return ScanDocStart();
beder's avatar
beder committed
116

beder's avatar
beder committed
117
		if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT))
118
			return ScanDocEnd();
beder's avatar
beder committed
119

beder's avatar
beder committed
120
		// flow start/end/entry
121
122
		if(INPUT.peek() == Keys::FlowSeqStart || INPUT.peek() == Keys::FlowMapStart)
			return ScanFlowStart();
beder's avatar
beder committed
123

124
125
126
		if(INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd)
			return ScanFlowEnd();
	
beder's avatar
beder committed
127
		if(INPUT.peek() == Keys::FlowEntry)
128
			return ScanFlowEntry();
beder's avatar
beder committed
129

beder's avatar
beder committed
130
		// block/map stuff
beder's avatar
beder committed
131
		if(Exp::BlockEntry.Matches(INPUT))
132
			return ScanBlockEntry();
beder's avatar
beder committed
133

beder's avatar
beder committed
134
		if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT))
135
			return ScanKey();
beder's avatar
beder committed
136

beder's avatar
beder committed
137
		if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT))
138
			return ScanValue();
beder's avatar
beder committed
139

beder's avatar
beder committed
140
		// alias/anchor
beder's avatar
beder committed
141
		if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor)
142
			return ScanAnchorOrAlias();
beder's avatar
beder committed
143

beder's avatar
beder committed
144
145
		// tag
		if(INPUT.peek() == Keys::Tag)
146
			return ScanTag();
beder's avatar
beder committed
147

beder's avatar
beder committed
148
149
		// special scalars
		if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar))
150
			return ScanBlockScalar();
beder's avatar
beder committed
151

beder's avatar
beder committed
152
		if(INPUT.peek() == '\'' || INPUT.peek() == '\"')
153
			return ScanQuotedScalar();
beder's avatar
beder committed
154
155

		// plain scalars
beder's avatar
beder committed
156
		if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT))
157
			return ScanPlainScalar();
beder's avatar
beder committed
158
159
160

		// don't know what it is!
		throw UnknownToken();
beder's avatar
beder committed
161
162
163
164
165
166
167
168
	}

	// ScanToNextToken
	// . Eats input until we reach the next token-like thing.
	void Scanner::ScanToNextToken()
	{
		while(1) {
			// first eat whitespace
beder's avatar
beder committed
169
			while(IsWhitespaceToBeEaten(INPUT.peek()))
170
				INPUT.eat(1);
beder's avatar
beder committed
171
172

			// then eat a comment
beder's avatar
beder committed
173
			if(Exp::Comment.Matches(INPUT)) {
beder's avatar
beder committed
174
				// eat until line break
beder's avatar
beder committed
175
				while(INPUT && !Exp::Break.Matches(INPUT))
176
					INPUT.eat(1);
beder's avatar
beder committed
177
178
179
			}

			// if it's NOT a line break, then we're done!
beder's avatar
beder committed
180
			if(!Exp::Break.Matches(INPUT))
beder's avatar
beder committed
181
182
183
				break;

			// otherwise, let's eat the line break and keep going
184
			int n = Exp::Break.Match(INPUT);
185
			INPUT.eat(n);
beder's avatar
beder committed
186

beder's avatar
beder committed
187
			// oh yeah, and let's get rid of that simple key
188
			VerifySimpleKey();
beder's avatar
beder committed
189

beder's avatar
beder committed
190
191
192
193
194
195
			// new line - we may be able to accept a simple key now
			if(m_flowLevel == 0)
				m_simpleKeyAllowed = true;
        }
	}

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
	///////////////////////////////////////////////////////////////////////
	// Misc. helpers

	// IsWhitespaceToBeEaten
	// . We can eat whitespace if:
	//   1. It's a space
	//   2. It's a tab, and we're either:
	//      a. In the flow context
	//      b. In the block context but not where a simple key could be allowed
	//         (i.e., not at the beginning of a line, or following '-', '?', or ':')
	bool Scanner::IsWhitespaceToBeEaten(char ch)
	{
		if(ch == ' ')
			return true;

		if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed))
			return true;

		return false;
	}

217
218
219
220
221
222
223
224
225
226
227
228
	// StartStream
	// . Set the initial conditions for starting a stream.
	void Scanner::StartStream()
	{
		m_startedStream = true;
		m_simpleKeyAllowed = true;
		m_indents.push(-1);
	}

	// EndStream
	// . Close out the stream, finish up, etc.
	void Scanner::EndStream()
229
	{
230
231
232
233
234
235
236
237
238
		// force newline
		if(INPUT.column > 0)
			INPUT.column = 0;

		PopIndentTo(-1);
		VerifyAllSimpleKeys();

		m_simpleKeyAllowed = false;
		m_endedStream = true;
239
240
	}

beder's avatar
beder committed
241
242
243
	// PushIndentTo
	// . Pushes an indentation onto the stack, and enqueues the
	//   proper token (sequence start or mapping start).
beder's avatar
beder committed
244
245
	// . Returns the token it generates (if any).
	Token *Scanner::PushIndentTo(int column, bool sequence)
beder's avatar
beder committed
246
247
248
	{
		// are we in flow?
		if(m_flowLevel > 0)
beder's avatar
beder committed
249
			return 0;
beder's avatar
beder committed
250
251
252

		// is this actually an indentation?
		if(column <= m_indents.top())
beder's avatar
beder committed
253
			return 0;
beder's avatar
beder committed
254
255
256
257

		// now push
		m_indents.push(column);
		if(sequence)
258
			m_tokens.push(new Token(TT_BLOCK_SEQ_START));
beder's avatar
beder committed
259
		else
260
			m_tokens.push(new Token(TT_BLOCK_MAP_START));
beder's avatar
beder committed
261
262

		return m_tokens.front();
beder's avatar
beder committed
263
264
265
266
267
268
269
270
271
272
273
274
275
276
	}

	// PopIndentTo
	// . Pops indentations off the stack until we reach 'column' indentation,
	//   and enqueues the proper token each time.
	void Scanner::PopIndentTo(int column)
	{
		// are we in flow?
		if(m_flowLevel > 0)
			return;

		// now pop away
		while(!m_indents.empty() && m_indents.top() > column) {
			m_indents.pop();
277
			m_tokens.push(new Token(TT_BLOCK_END));
beder's avatar
beder committed
278
279
		}
	}
beder's avatar
beder committed
280
}