external libraries: yaml-cpp version bump
[supercollider.git] / external_libraries / yaml-cpp-0.3.0 / src / scanscalar.cpp
blob064c0867a59e652bd79373bfad8e4ea1764d27d2
1 #include "scanscalar.h"
2 #include "scanner.h"
3 #include "exp.h"
4 #include "yaml-cpp/exceptions.h"
5 #include "token.h"
7 namespace YAML
9 // ScanScalar
10 // . This is where the scalar magic happens.
12 // . We do the scanning in three phases:
13 // 1. Scan until newline
14 // 2. Eat newline
15 // 3. Scan leading blanks.
17 // . Depending on the parameters given, we store or stop
18 // and different places in the above flow.
19 std::string ScanScalar(Stream& INPUT, ScanScalarParams& params)
21 bool foundNonEmptyLine = false;
22 bool pastOpeningBreak = (params.fold == FOLD_FLOW);
23 bool emptyLine = false, moreIndented = false;
24 int foldedNewlineCount = 0;
25 bool foldedNewlineStartedMoreIndented = false;
26 std::size_t lastEscapedChar = std::string::npos;
27 std::string scalar;
28 params.leadingSpaces = false;
30 while(INPUT) {
31 // ********************************
32 // Phase #1: scan until line ending
34 std::size_t lastNonWhitespaceChar = scalar.size();
35 bool escapedNewline = false;
36 while(!params.end.Matches(INPUT) && !Exp::Break().Matches(INPUT)) {
37 if(!INPUT)
38 break;
40 // document indicator?
41 if(INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) {
42 if(params.onDocIndicator == BREAK)
43 break;
44 else if(params.onDocIndicator == THROW)
45 throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR);
48 foundNonEmptyLine = true;
49 pastOpeningBreak = true;
51 // escaped newline? (only if we're escaping on slash)
52 if(params.escape == '\\' && Exp::EscBreak().Matches(INPUT)) {
53 // eat escape character and get out (but preserve trailing whitespace!)
54 INPUT.get();
55 lastNonWhitespaceChar = scalar.size();
56 lastEscapedChar = scalar.size();
57 escapedNewline = true;
58 break;
61 // escape this?
62 if(INPUT.peek() == params.escape) {
63 scalar += Exp::Escape(INPUT);
64 lastNonWhitespaceChar = scalar.size();
65 lastEscapedChar = scalar.size();
66 continue;
69 // otherwise, just add the damn character
70 char ch = INPUT.get();
71 scalar += ch;
72 if(ch != ' ' && ch != '\t')
73 lastNonWhitespaceChar = scalar.size();
76 // eof? if we're looking to eat something, then we throw
77 if(!INPUT) {
78 if(params.eatEnd)
79 throw ParserException(INPUT.mark(), ErrorMsg::EOF_IN_SCALAR);
80 break;
83 // doc indicator?
84 if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT))
85 break;
87 // are we done via character match?
88 int n = params.end.Match(INPUT);
89 if(n >= 0) {
90 if(params.eatEnd)
91 INPUT.eat(n);
92 break;
95 // do we remove trailing whitespace?
96 if(params.fold == FOLD_FLOW)
97 scalar.erase(lastNonWhitespaceChar);
99 // ********************************
100 // Phase #2: eat line ending
101 n = Exp::Break().Match(INPUT);
102 INPUT.eat(n);
104 // ********************************
105 // Phase #3: scan initial spaces
107 // first the required indentation
108 while(INPUT.peek() == ' ' && (INPUT.column() < params.indent || (params.detectIndent && !foundNonEmptyLine)))
109 INPUT.eat(1);
111 // update indent if we're auto-detecting
112 if(params.detectIndent && !foundNonEmptyLine)
113 params.indent = std::max(params.indent, INPUT.column());
115 // and then the rest of the whitespace
116 while(Exp::Blank().Matches(INPUT)) {
117 // we check for tabs that masquerade as indentation
118 if(INPUT.peek() == '\t'&& INPUT.column() < params.indent && params.onTabInIndentation == THROW)
119 throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION);
121 if(!params.eatLeadingWhitespace)
122 break;
124 INPUT.eat(1);
127 // was this an empty line?
128 bool nextEmptyLine = Exp::Break().Matches(INPUT);
129 bool nextMoreIndented = Exp::Blank().Matches(INPUT);
130 if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine)
131 foldedNewlineStartedMoreIndented = moreIndented;
133 // for block scalars, we always start with a newline, so we should ignore it (not fold or keep)
134 if(pastOpeningBreak) {
135 switch(params.fold) {
136 case DONT_FOLD:
137 scalar += "\n";
138 break;
139 case FOLD_BLOCK:
140 if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent)
141 scalar += " ";
142 else if(nextEmptyLine)
143 foldedNewlineCount++;
144 else
145 scalar += "\n";
147 if(!nextEmptyLine && foldedNewlineCount > 0) {
148 scalar += std::string(foldedNewlineCount - 1, '\n');
149 if(foldedNewlineStartedMoreIndented || nextMoreIndented | !foundNonEmptyLine)
150 scalar += "\n";
151 foldedNewlineCount = 0;
153 break;
154 case FOLD_FLOW:
155 if(nextEmptyLine)
156 scalar += "\n";
157 else if(!emptyLine && !nextEmptyLine && !escapedNewline)
158 scalar += " ";
159 break;
163 emptyLine = nextEmptyLine;
164 moreIndented = nextMoreIndented;
165 pastOpeningBreak = true;
167 // are we done via indentation?
168 if(!emptyLine && INPUT.column() < params.indent) {
169 params.leadingSpaces = true;
170 break;
174 // post-processing
175 if(params.trimTrailingSpaces) {
176 std::size_t pos = scalar.find_last_not_of(' ');
177 if(lastEscapedChar != std::string::npos) {
178 if(pos < lastEscapedChar || pos == std::string::npos)
179 pos = lastEscapedChar;
181 if(pos < scalar.size())
182 scalar.erase(pos + 1);
185 switch(params.chomp) {
186 case CLIP: {
187 std::size_t pos = scalar.find_last_not_of('\n');
188 if(lastEscapedChar != std::string::npos) {
189 if(pos < lastEscapedChar || pos == std::string::npos)
190 pos = lastEscapedChar;
192 if(pos == std::string::npos)
193 scalar.erase();
194 else if(pos + 1 < scalar.size())
195 scalar.erase(pos + 2);
196 } break;
197 case STRIP: {
198 std::size_t pos = scalar.find_last_not_of('\n');
199 if(lastEscapedChar != std::string::npos) {
200 if(pos < lastEscapedChar || pos == std::string::npos)
201 pos = lastEscapedChar;
203 if(pos == std::string::npos)
204 scalar.erase();
205 else if(pos < scalar.size())
206 scalar.erase(pos + 1);
207 } break;
208 default:
209 break;
212 return scalar;