sequence.cpp 3.84 KB
Newer Older
1
#include "crt.h"
2
3
#include "sequence.h"
#include "node.h"
4
5
#include "scanner.h"
#include "token.h"
6
7
8

namespace YAML
{
Jesse Beder's avatar
Jesse Beder committed
9
	Sequence::Sequence()
10
	{
Jesse Beder's avatar
Jesse Beder committed
11

12
13
14
	}

	Sequence::~Sequence()
15
16
17
18
19
	{
		Clear();
	}

	void Sequence::Clear()
20
21
22
	{
		for(unsigned i=0;i<m_data.size();i++)
			delete m_data[i];
23
		m_data.clear();
24
	}
25

26
	bool Sequence::GetBegin(std::vector <Node *>::const_iterator& it) const
27
28
29
30
31
	{
		it = m_data.begin();
		return true;
	}

32
	bool Sequence::GetEnd(std::vector <Node *>::const_iterator& it) const
33
34
35
36
37
	{
		it = m_data.end();
		return true;
	}

38
39
40
41
42
43
44
45
46
47
48
49
	Node *Sequence::GetNode(unsigned i) const
	{
		if(i < m_data.size())
			return m_data[i];
		return 0;
	}

	unsigned Sequence::GetSize() const
	{
		return m_data.size();
	}

50
	void Sequence::Parse(Scanner *pScanner, const ParserState& state)
51
	{
52
53
54
		Clear();

		// split based on start token
55
		Token& token = pScanner->PeekToken();
56

57
		switch(token.type) {
58
59
60
			case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break;
			case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break;
			case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break;
61
62
63
		}
	}

64
	void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state)
65
	{
66
		// eat start token
67
		pScanner->PopToken();
68

69
		while(1) {
70
			if(pScanner->IsEmpty())
71
				throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ);
72

73
74
75
			Token token = pScanner->PeekToken();
			if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END)
				throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ);
76

77
78
			pScanner->PopToken();
			if(token.type == TT_BLOCK_END)
79
80
81
82
				break;

			Node *pNode = new Node;
			m_data.push_back(pNode);
83
			pNode->Parse(pScanner, state);
84
85
86
		}
	}

87
	void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state)
88
	{
89
90
		while(1) {
			// we're actually *allowed* to have no tokens at some point
91
			if(pScanner->IsEmpty())
92
93
94
				break;

			// and we end at anything other than a block entry
95
96
			Token& token = pScanner->PeekToken();
			if(token.type != TT_BLOCK_ENTRY)
97
98
				break;

99
			pScanner->PopToken();
100
101
102

			Node *pNode = new Node;
			m_data.push_back(pNode);
103
			pNode->Parse(pScanner, state);
104
		}
105
106
	}

107
	void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state)
108
	{
109
		// eat start token
110
		pScanner->PopToken();
111

112
		while(1) {
113
			if(pScanner->IsEmpty())
114
				throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW);
115
116

			// first check for end
117
118
			if(pScanner->PeekToken().type == TT_FLOW_SEQ_END) {
				pScanner->PopToken();
119
120
121
122
123
124
				break;
			}

			// then read the node
			Node *pNode = new Node;
			m_data.push_back(pNode);
125
			pNode->Parse(pScanner, state);
126
127

			// now eat the separator (or could be a sequence end, which we ignore - but if it's neither, then it's a bad node)
128
129
130
131
132
			Token& token = pScanner->PeekToken();
			if(token.type == TT_FLOW_ENTRY)
				pScanner->PopToken();
			else if(token.type != TT_FLOW_SEQ_END)
				throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW);
133
134
135
		}
	}

136
	void Sequence::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
137
	{
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
		if(startedLine && !onlyOneCharOnLine)
			out << std::endl;

		for(unsigned i=0;i<m_data.size();i++) {
			if((startedLine && !onlyOneCharOnLine) || i > 0) {
				for(int j=0;j<indent;j++)
					out  << "  ";
			}

			out << "- ";
			m_data[i]->Write(out, indent + 1, true, i > 0 || !startedLine || onlyOneCharOnLine);
		}

		if(m_data.empty())
			out << std::endl;
153
	}
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

	int Sequence::Compare(Content *pContent)
	{
		return -pContent->Compare(this);
	}

	int Sequence::Compare(Sequence *pSeq)
	{
		unsigned n = m_data.size(), m = pSeq->m_data.size();
		if(n < m)
			return -1;
		else if(n > m)
			return 1;

		for(unsigned i=0;i<n;i++) {
			int cmp = m_data[i]->Compare(*pSeq->m_data[i]);
			if(cmp != 0)
				return cmp;
		}

		return 0;
	}
176
}