supernova: allocators - fix construct method
[supercollider.git] / external_libraries / yaml-cpp-0.2.6 / src / scanscalar.cpp
blob2a7afa932c1e70eb83240368370991f020cf4064
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::string scalar;
27 params.leadingSpaces = false;
29 while(INPUT) {
30 // ********************************
31 // Phase #1: scan until line ending
33 std::size_t lastNonWhitespaceChar = scalar.size();
34 bool escapedNewline = false;
35 while(!params.end.Matches(INPUT) && !Exp::Break().Matches(INPUT)) {
36 if(!INPUT)
37 break;
39 // document indicator?
40 if(INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) {
41 if(params.onDocIndicator == BREAK)
42 break;
43 else if(params.onDocIndicator == THROW)
44 throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR);
47 foundNonEmptyLine = true;
48 pastOpeningBreak = true;
50 // escaped newline? (only if we're escaping on slash)
51 if(params.escape == '\\' && Exp::EscBreak().Matches(INPUT)) {
52 // eat escape character and get out (but preserve trailing whitespace!)
53 INPUT.get();
54 lastNonWhitespaceChar = scalar.size();
55 escapedNewline = true;
56 break;
59 // escape this?
60 if(INPUT.peek() == params.escape) {
61 scalar += Exp::Escape(INPUT);
62 lastNonWhitespaceChar = scalar.size();
63 continue;
66 // otherwise, just add the damn character
67 char ch = INPUT.get();
68 scalar += ch;
69 if(ch != ' ' && ch != '\t')
70 lastNonWhitespaceChar = scalar.size();
73 // eof? if we're looking to eat something, then we throw
74 if(!INPUT) {
75 if(params.eatEnd)
76 throw ParserException(INPUT.mark(), ErrorMsg::EOF_IN_SCALAR);
77 break;
80 // doc indicator?
81 if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT))
82 break;
84 // are we done via character match?
85 int n = params.end.Match(INPUT);
86 if(n >= 0) {
87 if(params.eatEnd)
88 INPUT.eat(n);
89 break;
92 // do we remove trailing whitespace?
93 if(params.fold == FOLD_FLOW)
94 scalar.erase(lastNonWhitespaceChar);
96 // ********************************
97 // Phase #2: eat line ending
98 n = Exp::Break().Match(INPUT);
99 INPUT.eat(n);
101 // ********************************
102 // Phase #3: scan initial spaces
104 // first the required indentation
105 while(INPUT.peek() == ' ' && (INPUT.column() < params.indent || (params.detectIndent && !foundNonEmptyLine)))
106 INPUT.eat(1);
108 // update indent if we're auto-detecting
109 if(params.detectIndent && !foundNonEmptyLine)
110 params.indent = std::max(params.indent, INPUT.column());
112 // and then the rest of the whitespace
113 while(Exp::Blank().Matches(INPUT)) {
114 // we check for tabs that masquerade as indentation
115 if(INPUT.peek() == '\t'&& INPUT.column() < params.indent && params.onTabInIndentation == THROW)
116 throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION);
118 if(!params.eatLeadingWhitespace)
119 break;
121 INPUT.eat(1);
124 // was this an empty line?
125 bool nextEmptyLine = Exp::Break().Matches(INPUT);
126 bool nextMoreIndented = Exp::Blank().Matches(INPUT);
127 if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine)
128 foldedNewlineStartedMoreIndented = moreIndented;
130 // for block scalars, we always start with a newline, so we should ignore it (not fold or keep)
131 if(pastOpeningBreak) {
132 switch(params.fold) {
133 case DONT_FOLD:
134 scalar += "\n";
135 break;
136 case FOLD_BLOCK:
137 if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent)
138 scalar += " ";
139 else if(nextEmptyLine)
140 foldedNewlineCount++;
141 else
142 scalar += "\n";
144 if(!nextEmptyLine && foldedNewlineCount > 0) {
145 scalar += std::string(foldedNewlineCount - 1, '\n');
146 if(foldedNewlineStartedMoreIndented || nextMoreIndented | !foundNonEmptyLine)
147 scalar += "\n";
148 foldedNewlineCount = 0;
150 break;
151 case FOLD_FLOW:
152 if(nextEmptyLine)
153 scalar += "\n";
154 else if(!emptyLine && !nextEmptyLine && !escapedNewline)
155 scalar += " ";
156 break;
160 emptyLine = nextEmptyLine;
161 moreIndented = nextMoreIndented;
162 pastOpeningBreak = true;
164 // are we done via indentation?
165 if(!emptyLine && INPUT.column() < params.indent) {
166 params.leadingSpaces = true;
167 break;
171 // post-processing
172 if(params.trimTrailingSpaces) {
173 std::size_t pos = scalar.find_last_not_of(' ');
174 if(pos < scalar.size())
175 scalar.erase(pos + 1);
178 switch(params.chomp) {
179 case CLIP: {
180 const std::size_t pos = scalar.find_last_not_of('\n');
181 if(pos == std::string::npos)
182 scalar.erase();
183 else if(pos + 1 < scalar.size())
184 scalar.erase(pos + 2);
185 } break;
186 case STRIP: {
187 const std::size_t pos = scalar.find_last_not_of('\n');
188 if(pos == std::string::npos)
189 scalar.erase();
190 else if(pos < scalar.size())
191 scalar.erase(pos + 1);
192 } break;
193 default:
194 break;
197 return scalar;