scanscalar.cpp
Go to the documentation of this file.
00001 #include "scanscalar.h"
00002 #include "scanner.h"
00003 #include "exp.h"
00004 #include "yaml-cpp-pm/exceptions.h"
00005 #include "token.h"
00006 
00007 namespace YAML_PM
00008 {
00009         // ScanScalar
00010         // . This is where the scalar magic happens.
00011         //
00012         // . We do the scanning in three phases:
00013         //   1. Scan until newline
00014         //   2. Eat newline
00015         //   3. Scan leading blanks.
00016         //
00017         // . Depending on the parameters given, we store or stop
00018         //   and different places in the above flow.
00019         std::string ScanScalar(Stream& INPUT, ScanScalarParams& params)
00020         {
00021                 bool foundNonEmptyLine = false;
00022                 bool pastOpeningBreak = (params.fold == FOLD_FLOW);
00023                 bool emptyLine = false, moreIndented = false;
00024                 int foldedNewlineCount = 0;
00025                 bool foldedNewlineStartedMoreIndented = false;
00026         std::size_t lastEscapedChar = std::string::npos;
00027                 std::string scalar;
00028                 params.leadingSpaces = false;
00029 
00030                 while(INPUT) {
00031                         // ********************************
00032                         // Phase #1: scan until line ending
00033                         
00034                         std::size_t lastNonWhitespaceChar = scalar.size();
00035                         bool escapedNewline = false;
00036                         while(!params.end.Matches(INPUT) && !Exp::Break().Matches(INPUT)) {
00037                                 if(!INPUT)
00038                                         break;
00039 
00040                                 // document indicator?
00041                                 if(INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) {
00042                                         if(params.onDocIndicator == BREAK)
00043                                                 break;
00044                                         else if(params.onDocIndicator == THROW)
00045                                                 throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR);
00046                                 }
00047 
00048                                 foundNonEmptyLine = true;
00049                                 pastOpeningBreak = true;
00050 
00051                                 // escaped newline? (only if we're escaping on slash)
00052                                 if(params.escape == '\\' && Exp::EscBreak().Matches(INPUT)) {
00053                                         // eat escape character and get out (but preserve trailing whitespace!)
00054                                         INPUT.get();
00055                                         lastNonWhitespaceChar = scalar.size();
00056                     lastEscapedChar = scalar.size();
00057                                         escapedNewline = true;
00058                                         break;
00059                                 }
00060 
00061                                 // escape this?
00062                                 if(INPUT.peek() == params.escape) {
00063                                         scalar += Exp::Escape(INPUT);
00064                                         lastNonWhitespaceChar = scalar.size();
00065                     lastEscapedChar = scalar.size();
00066                                         continue;
00067                                 }
00068 
00069                                 // otherwise, just add the damn character
00070                                 char ch = INPUT.get();
00071                                 scalar += ch;
00072                                 if(ch != ' ' && ch != '\t')
00073                                         lastNonWhitespaceChar = scalar.size();
00074                         }
00075 
00076                         // eof? if we're looking to eat something, then we throw
00077                         if(!INPUT) {
00078                                 if(params.eatEnd)
00079                                         throw ParserException(INPUT.mark(), ErrorMsg::EOF_IN_SCALAR);
00080                                 break;
00081                         }
00082 
00083                         // doc indicator?
00084                         if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT))
00085                                 break;
00086 
00087                         // are we done via character match?
00088                         int n = params.end.Match(INPUT);
00089                         if(n >= 0) {
00090                                 if(params.eatEnd)
00091                                         INPUT.eat(n);
00092                                 break;
00093                         }
00094                         
00095                         // do we remove trailing whitespace?
00096                         if(params.fold == FOLD_FLOW)
00097                                 scalar.erase(lastNonWhitespaceChar);
00098                         
00099                         // ********************************
00100                         // Phase #2: eat line ending
00101                         n = Exp::Break().Match(INPUT);
00102                         INPUT.eat(n);
00103 
00104                         // ********************************
00105                         // Phase #3: scan initial spaces
00106 
00107                         // first the required indentation
00108                         while(INPUT.peek() == ' ' && (INPUT.column() < params.indent || (params.detectIndent && !foundNonEmptyLine)))
00109                                 INPUT.eat(1);
00110 
00111                         // update indent if we're auto-detecting
00112                         if(params.detectIndent && !foundNonEmptyLine)
00113                                 params.indent = std::max(params.indent, INPUT.column());
00114 
00115                         // and then the rest of the whitespace
00116                         while(Exp::Blank().Matches(INPUT)) {
00117                                 // we check for tabs that masquerade as indentation
00118                                 if(INPUT.peek() == '\t'&& INPUT.column() < params.indent && params.onTabInIndentation == THROW)
00119                                         throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION);
00120 
00121                                 if(!params.eatLeadingWhitespace)
00122                                         break;
00123 
00124                                 INPUT.eat(1);
00125                         }
00126 
00127                         // was this an empty line?
00128                         bool nextEmptyLine = Exp::Break().Matches(INPUT);
00129                         bool nextMoreIndented = Exp::Blank().Matches(INPUT);
00130                         if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine)
00131                                 foldedNewlineStartedMoreIndented = moreIndented;
00132 
00133                         // for block scalars, we always start with a newline, so we should ignore it (not fold or keep)
00134                         if(pastOpeningBreak) {
00135                                 switch(params.fold) {
00136                                         case DONT_FOLD:
00137                                                 scalar += "\n";
00138                                                 break;
00139                                         case FOLD_BLOCK:
00140                                                 if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent)
00141                                                         scalar += " ";
00142                                                 else if(nextEmptyLine)
00143                                                         foldedNewlineCount++;
00144                                                 else
00145                                                         scalar += "\n";
00146                                                 
00147                                                 if(!nextEmptyLine && foldedNewlineCount > 0) {
00148                                                         scalar += std::string(foldedNewlineCount - 1, '\n');
00149                                                         if(foldedNewlineStartedMoreIndented || nextMoreIndented | !foundNonEmptyLine)
00150                                                                 scalar += "\n";
00151                                                         foldedNewlineCount = 0;
00152                                                 }
00153                                                 break;
00154                                         case FOLD_FLOW:
00155                                                 if(nextEmptyLine)
00156                                                         scalar += "\n";
00157                                                 else if(!emptyLine && !nextEmptyLine && !escapedNewline)
00158                                                         scalar += " ";
00159                                                 break;
00160                                 }
00161                         }
00162 
00163                         emptyLine = nextEmptyLine;
00164                         moreIndented = nextMoreIndented;
00165                         pastOpeningBreak = true;
00166 
00167                         // are we done via indentation?
00168                         if(!emptyLine && INPUT.column() < params.indent) {
00169                                 params.leadingSpaces = true;
00170                                 break;
00171                         }
00172                 }
00173 
00174                 // post-processing
00175                 if(params.trimTrailingSpaces) {
00176                         std::size_t pos = scalar.find_last_not_of(' ');
00177             if(lastEscapedChar != std::string::npos) {
00178                 if(pos < lastEscapedChar || pos == std::string::npos)
00179                     pos = lastEscapedChar;
00180             }
00181                         if(pos < scalar.size())
00182                                 scalar.erase(pos + 1);
00183                 }
00184 
00185                 switch(params.chomp) {
00186                         case CLIP: {
00187                                 std::size_t pos = scalar.find_last_not_of('\n');
00188                 if(lastEscapedChar != std::string::npos) {
00189                     if(pos < lastEscapedChar || pos == std::string::npos)
00190                         pos = lastEscapedChar;
00191                 }
00192                                 if(pos == std::string::npos)
00193                                         scalar.erase();
00194                                 else if(pos + 1 < scalar.size())
00195                                         scalar.erase(pos + 2);
00196                         } break;
00197                         case STRIP: {
00198                                 std::size_t pos = scalar.find_last_not_of('\n');
00199                 if(lastEscapedChar != std::string::npos) {
00200                     if(pos < lastEscapedChar || pos == std::string::npos)
00201                         pos = lastEscapedChar;
00202                 }
00203                                 if(pos == std::string::npos)
00204                                         scalar.erase();
00205                                 else if(pos < scalar.size())
00206                                         scalar.erase(pos + 1);
00207                         } break;
00208                         default:
00209                                 break;
00210                 }
00211 
00212                 return scalar;
00213         }
00214 }


libpointmatcher
Author(s):
autogenerated on Mon Sep 14 2015 02:59:06