scanscalar.cpp
Go to the documentation of this file.
1 #include "scanscalar.h"
2 #include "scanner.h"
3 #include "exp.h"
5 #include "token.h"
6 
7 namespace YAML_PM
8 {
9  // ScanScalar
10  // . This is where the scalar magic happens.
11  //
12  // . We do the scanning in three phases:
13  // 1. Scan until newline
14  // 2. Eat newline
15  // 3. Scan leading blanks.
16  //
17  // . Depending on the parameters given, we store or stop
18  // and different places in the above flow.
20  {
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;
29 
30  while(INPUT) {
31  // ********************************
32  // Phase #1: scan until line ending
33 
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;
39 
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)
46  }
47 
48  foundNonEmptyLine = true;
49  pastOpeningBreak = true;
50 
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;
59  }
60 
61  // escape this?
62  if(INPUT.peek() == params.escape) {
63  scalar += Exp::Escape(INPUT);
64  lastNonWhitespaceChar = scalar.size();
65  lastEscapedChar = scalar.size();
66  continue;
67  }
68 
69  // otherwise, just add the damn character
70  char ch = INPUT.get();
71  scalar += ch;
72  if(ch != ' ' && ch != '\t')
73  lastNonWhitespaceChar = scalar.size();
74  }
75 
76  // eof? if we're looking to eat something, then we throw
77  if(!INPUT) {
78  if(params.eatEnd)
80  break;
81  }
82 
83  // doc indicator?
84  if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT))
85  break;
86 
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;
93  }
94 
95  // do we remove trailing whitespace?
96  if(params.fold == FOLD_FLOW)
97  scalar.erase(lastNonWhitespaceChar);
98 
99  // ********************************
100  // Phase #2: eat line ending
101  n = Exp::Break().Match(INPUT);
102  INPUT.eat(n);
103 
104  // ********************************
105  // Phase #3: scan initial spaces
106 
107  // first the required indentation
108  while(INPUT.peek() == ' ' && (INPUT.column() < params.indent || (params.detectIndent && !foundNonEmptyLine)))
109  INPUT.eat(1);
110 
111  // update indent if we're auto-detecting
112  if(params.detectIndent && !foundNonEmptyLine)
113  params.indent = std::max(params.indent, INPUT.column());
114 
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)
120 
121  if(!params.eatLeadingWhitespace)
122  break;
123 
124  INPUT.eat(1);
125  }
126 
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;
132 
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";
146 
147  if(!nextEmptyLine && foldedNewlineCount > 0) {
148  scalar += std::string(foldedNewlineCount - 1, '\n');
149  if(foldedNewlineStartedMoreIndented || nextMoreIndented | !foundNonEmptyLine)
150  scalar += "\n";
151  foldedNewlineCount = 0;
152  }
153  break;
154  case FOLD_FLOW:
155  if(nextEmptyLine)
156  scalar += "\n";
157  else if(!emptyLine && !nextEmptyLine && !escapedNewline)
158  scalar += " ";
159  break;
160  }
161  }
162 
163  emptyLine = nextEmptyLine;
164  moreIndented = nextMoreIndented;
165  pastOpeningBreak = true;
166 
167  // are we done via indentation?
168  if(!emptyLine && INPUT.column() < params.indent) {
169  params.leadingSpaces = true;
170  break;
171  }
172  }
173 
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;
180  }
181  if(pos < scalar.size())
182  scalar.erase(pos + 1);
183  }
184 
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;
191  }
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;
202  }
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;
210  }
211 
212  return scalar;
213  }
214 }
std::string ScanScalar(Stream &INPUT, ScanScalarParams &params)
Definition: scanscalar.cpp:19
::std::string string
Definition: gtest.h:1979
const RegEx & EscBreak()
Definition: exp.h:160
const RegEx & Break()
Definition: exp.h:34
const char *const EOF_IN_SCALAR
Definition: exceptions.h:42
void eat(int n=1)
Definition: stream.cpp:272
int column() const
Definition: stream.h:41
int Match(const std::string &str) const
Definition: regeximpl.h:42
const char *const DOC_IN_SCALAR
Definition: exceptions.h:41
char peek() const
Definition: stream.cpp:228
const RegEx & Blank()
Definition: exp.h:30
const char *const TAB_IN_INDENTATION
Definition: exceptions.h:44
const Mark mark() const
Definition: stream.h:38
const RegEx & DocIndicator()
Definition: exp.h:85
std::string Escape(Stream &in, int codeLength)
Definition: exp.cpp:38
bool Matches(char ch) const
Definition: regeximpl.h:16


libpointmatcher
Author(s):
autogenerated on Sat May 27 2023 02:38:03