• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef textParser_DEFINED
9 #define textParser_DEFINED
10 
11 #include <functional>
12 
13 #include "bookmaker.h"
14 
15 class BmhParser;
16 class Definition;
17 
18 class TextParser : public NonAssignable {
TextParser()19     TextParser() {}  // only for ParserCommon, TextParserSave
20     friend class ParserCommon;
21     friend class TextParserSave;
22 public:
~TextParser()23     virtual ~TextParser() {}
24 
TextParser(string fileName,const char * start,const char * end,int lineCount)25     TextParser(string fileName, const char* start, const char* end, int lineCount)
26         : fFileName(fileName)
27         , fStart(start)
28         , fLine(start)
29         , fChar(start)
30         , fEnd(end)
31         , fLineCount(lineCount)
32     {
33     }
34 
35     TextParser(const Definition* );
36 
anyOf(const char * str)37     const char* anyOf(const char* str) const {
38         const char* ptr = fChar;
39         while (ptr < fEnd) {
40             if (strchr(str, ptr[0])) {
41                 return ptr;
42             }
43             ++ptr;
44         }
45         return nullptr;
46     }
47 
anyOf(const char * wordStart,const char * wordList[],size_t wordListCount)48     const char* anyOf(const char* wordStart, const char* wordList[], size_t wordListCount) const {
49         const char** wordPtr = wordList;
50         const char** wordEnd = wordPtr + wordListCount;
51         const size_t matchLen = fChar - wordStart;
52         while (wordPtr < wordEnd) {
53             const char* word = *wordPtr++;
54             if (strlen(word) == matchLen && !strncmp(wordStart, word, matchLen)) {
55                 return word;
56             }
57         }
58         return nullptr;
59     }
60 
61     // words must be alpha only
anyWord(const vector<string> & wordList,int spaces)62     string anyWord(const vector<string>& wordList, int spaces) const {
63         const char* matchStart = fChar;
64         do {
65             int count = spaces;
66             while (matchStart < fEnd && !isalpha(matchStart[0])) {
67                 ++matchStart;
68             }
69             const char* matchEnd = matchStart;
70             const char* nextWord = nullptr;
71             while (matchEnd < fEnd) {
72                 if (isalpha(matchEnd[0])) {
73                 } else if (' ' == matchEnd[0] && --count >= 0) {
74                     if (!nextWord) {
75                         nextWord = matchEnd;
76                     }
77                 } else {
78                     break;
79                 }
80                 ++matchEnd;
81             }
82             size_t matchLen = matchEnd - matchStart;
83             for (auto word : wordList) {
84                 if (word.length() != matchLen) {
85                     continue;
86                 }
87                 for (unsigned index = 0; index < matchLen; ++index) {
88                     if (tolower(matchStart[index]) != word[index]) {
89                         goto nextWord;
90                     }
91                 }
92                 return word;
93         nextWord: ;
94             }
95             matchStart = nextWord ? nextWord : matchEnd;
96         } while (matchStart < fEnd);
97         return "";
98     }
99 
back(const char * pattern)100     bool back(const char* pattern) {
101         size_t len = strlen(pattern);
102         const char* start = fChar - len;
103         if (start <= fStart) {
104             return false;
105         }
106         if (strncmp(start, pattern, len)) {
107             return false;
108         }
109         fChar = start;
110         return true;
111     }
112 
backup(const char * pattern)113     char backup(const char* pattern) const {
114         size_t len = strlen(pattern);
115         const char* start = fChar - len;
116         if (start <= fStart) {
117             return '\0';
118         }
119         if (strncmp(start, pattern, len)) {
120             return '\0';
121         }
122         return start[-1];
123     }
124 
backupWord()125     void backupWord() {
126         while (fChar > fStart && isalpha(fChar[-1])) {
127             --fChar;
128         }
129     }
130 
contains(const char * match,const char * lineEnd,const char ** loc)131     bool contains(const char* match, const char* lineEnd, const char** loc) const {
132         const char* result = this->strnstr(match, lineEnd);
133         if (loc) {
134             *loc = result;
135         }
136         return result;
137     }
138 
containsWord(const char * match,const char * lineEnd,const char ** loc)139     bool containsWord(const char* match, const char* lineEnd, const char** loc) {
140         size_t len = strlen(match);
141         do {
142             const char* result = this->strnstr(match, lineEnd);
143             if (!result) {
144                 return false;
145             }
146             if ((result > fStart && isalnum(result[-1])) || (result + len < fEnd
147                     && isalnum(result[len]))) {
148                 fChar = result + len;
149                 continue;
150             }
151             if (loc) {
152                 *loc = result;
153             }
154             return true;
155         } while (true);
156     }
157 
158     // either /n/n or /n# will stop parsing a typedef
doubleLF()159     const char* doubleLF() const {
160         const char* ptr = fChar - 1;
161         const char* doubleStart = nullptr;
162         while (++ptr < fEnd) {
163             if (!doubleStart) {
164                 if ('\n' == ptr[0]) {
165                     doubleStart = ptr;
166                 }
167                 continue;
168             }
169             if ('\n' == ptr[0] || '#' == ptr[0]) {
170                 return doubleStart;
171             }
172             if (' ' < ptr[0]) {
173                 doubleStart = nullptr;
174             }
175         }
176         return nullptr;
177     }
178 
endsWith(const char * match)179     bool endsWith(const char* match) {
180         int matchLen = strlen(match);
181         if (matchLen > fChar - fLine) {
182             return false;
183         }
184         return !strncmp(fChar - matchLen, match, matchLen);
185     }
186 
eof()187     bool eof() const { return fChar >= fEnd; }
188 
lineEnd()189     const char* lineEnd() const {
190         const char* ptr = fChar;
191         do {
192             if (ptr >= fEnd) {
193                 return ptr;
194             }
195             char test = *ptr++;
196             if (test == '\n' || test == '\0') {
197                 break;
198             }
199         } while (true);
200         return ptr;
201     }
202 
lineLength()203     ptrdiff_t lineLength() const {
204         return this->lineEnd() - fLine;
205     }
206 
207     bool match(TextParser* );
208 
next()209     char next() {
210         SkASSERT(fChar < fEnd);
211         char result = *fChar++;
212         if ('\n' == result) {
213             ++fLineCount;
214             fLine = fChar;
215         }
216         return result;
217     }
218 
peek()219     char peek() const { SkASSERT(fChar < fEnd); return *fChar; }
220 
restorePlace(const TextParser & save)221     void restorePlace(const TextParser& save) {
222         fChar = save.fChar;
223         fLine = save.fLine;
224         fLineCount = save.fLineCount;
225     }
226 
savePlace(TextParser * save)227     void savePlace(TextParser* save) {
228         save->fChar = fChar;
229         save->fLine = fLine;
230         save->fLineCount = fLineCount;
231     }
232 
233     void reportError(const char* errorStr) const;
234     static string ReportFilename(string file);
235     void reportWarning(const char* errorStr) const;
236 
reportError(const char * errorStr)237     template <typename T> T reportError(const char* errorStr) const {
238         this->reportError(errorStr);
239         return T();
240     }
241 
sentenceEnd(const char * check)242     bool sentenceEnd(const char* check) const {
243         while (check > fStart) {
244             --check;
245             if (' ' < check[0] && '.' != check[0]) {
246                 return false;
247             }
248             if ('.' == check[0]) {
249                 return ' ' >= check[1];
250             }
251             if ('\n' == check[0] && '\n' == check[1]) {
252                 return true;
253             }
254         }
255         return true;
256     }
257 
258     void setForErrorReporting(const Definition* , const char* );
259 
skipToBalancedEndBracket(char startB,char endB)260     bool skipToBalancedEndBracket(char startB, char endB) {
261         SkASSERT(fChar < fEnd);
262         SkASSERT(startB == fChar[0]);
263         int startCount = 0;
264         do {
265             char test = this->next();
266             startCount += startB == test;
267             startCount -= endB  == test;
268         } while (startCount && fChar < fEnd);
269         return !startCount;
270     }
271 
272     bool skipToEndBracket(char endBracket, const char* end = nullptr) {
273         if (nullptr == end) {
274             end = fEnd;
275         }
276         while (fChar[0] != endBracket) {
277             if (fChar >= end) {
278                 return false;
279             }
280             (void) this->next();
281         }
282         return true;
283     }
284 
skipToEndBracket(const char * endBracket)285     bool skipToEndBracket(const char* endBracket) {
286         size_t len = strlen(endBracket);
287         while (strncmp(fChar, endBracket, len)) {
288             if (fChar >= fEnd) {
289                 return false;
290             }
291             (void) this->next();
292         }
293         return true;
294     }
295 
skipLine()296     bool skipLine() {
297         return skipToEndBracket('\n');
298     }
299 
skipTo(const char * skip)300     void skipTo(const char* skip) {
301        while (fChar < skip) {
302            this->next();
303        }
304     }
305 
skipToAlpha()306     void skipToAlpha() {
307         while (fChar < fEnd && !isalpha(fChar[0])) {
308             fChar++;
309         }
310     }
311 
312     // returns true if saw close brace
skipToAlphaNum()313     bool skipToAlphaNum() {
314         bool sawCloseBrace = false;
315         while (fChar < fEnd && !isalnum(fChar[0])) {
316             sawCloseBrace |= '}' == *fChar++;
317         }
318         return sawCloseBrace;
319     }
320 
skipExact(const char * pattern)321     bool skipExact(const char* pattern) {
322         if (!this->startsWith(pattern)) {
323             return false;
324         }
325         this->skipName(pattern);
326         return true;
327     }
328 
329     // differs from skipToNonAlphaNum in that a.b isn't considered a full name,
330     // since a.b can't be found as a named definition
skipFullName()331     void skipFullName() {
332         do {
333             char last = '\0';
334             while (fChar < fEnd && (isalnum(fChar[0])
335                     || '_' == fChar[0]  /* || '-' == fChar[0] */
336                     || (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1]))) {
337                 if (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1]) {
338                     fChar++;
339                 }
340                 last = fChar[0];
341                 fChar++;
342             }
343             if (fChar + 1 >= fEnd || '/' != fChar[0] || !isalpha(last) || !isalpha(fChar[1])) {
344                 break;  // stop unless pattern is xxx/xxx as in I/O
345             }
346             fChar++; // skip slash
347         } while (true);
348     }
349 
skipToLineBalance(char open,char close)350     int skipToLineBalance(char open, char close) {
351         int match = 0;
352         while (!this->eof() && '\n' != fChar[0]) {
353             match += open == this->peek();
354             match -= close == this->next();
355         }
356         return match;
357     }
358 
skipToLineStart()359     bool skipToLineStart() {
360         if (!this->skipLine()) {
361             return false;
362         }
363         if (!this->eof()) {
364             return this->skipWhiteSpace();
365         }
366         return true;
367     }
368 
skipToLineStart(int * indent,bool * sawReturn)369     void skipToLineStart(int* indent, bool* sawReturn) {
370         SkAssertResult(this->skipLine());
371         this->skipWhiteSpace(indent, sawReturn);
372     }
373 
skipLower()374     void skipLower() {
375         while (fChar < fEnd && (islower(fChar[0]) || '_' == fChar[0])) {
376             fChar++;
377         }
378     }
379 
skipToNonAlphaNum()380     void skipToNonAlphaNum() {
381         while (fChar < fEnd && (isalnum(fChar[0]) || '_' == fChar[0])) {
382             fChar++;
383         }
384     }
385 
skipToNonName()386     void skipToNonName() {
387         while (fChar < fEnd && (isalnum(fChar[0])
388                 || '_' == fChar[0] || '-' == fChar[0]
389                 || (':' == fChar[0] && fChar + 1 < fEnd && ':' == fChar[1])
390                 || ('.' == fChar[0] && fChar + 1 < fEnd && isalpha(fChar[1])))) {
391             if (':' == fChar[0] && fChar +1 < fEnd && ':' == fChar[1]) {
392                 fChar++;
393             }
394             fChar++;
395         }
396     }
397 
skipPhraseName()398     void skipPhraseName() {
399         while (fChar < fEnd && (islower(fChar[0]) || '_' == fChar[0])) {
400             fChar++;
401         }
402     }
403 
skipToSpace()404     void skipToSpace() {
405         while (fChar < fEnd && ' ' != fChar[0]) {
406             fChar++;
407         }
408     }
409 
skipToWhiteSpace()410     void skipToWhiteSpace() {
411         while (fChar < fEnd && ' ' < fChar[0]) {
412             fChar++;
413         }
414     }
415 
skipName(const char * word)416     bool skipName(const char* word) {
417         size_t len = strlen(word);
418         if (len <= (size_t) (fEnd - fChar) && !strncmp(word, fChar, len)) {
419             for (size_t i = 0; i < len; ++i) {
420                 this->next();
421             }
422         }
423         return this->eof() || ' ' >= fChar[0];
424     }
425 
skipSpace()426     bool skipSpace() {
427         while (' ' == this->peek()) {
428             (void) this->next();
429             if (fChar >= fEnd) {
430                 return false;
431             }
432         }
433         return true;
434     }
435 
skipWord(const char * word)436     bool skipWord(const char* word) {
437         if (!this->skipWhiteSpace()) {
438             return false;
439         }
440         const char* save = fChar;
441         if (!this->skipName(word)) {
442             fChar = save;
443             return false;
444         }
445         if (!this->skipWhiteSpace()) {
446             return false;
447         }
448         return true;
449     }
450 
skipWhiteSpace()451     bool skipWhiteSpace() {
452         while (' ' >= this->peek()) {
453             (void) this->next();
454             if (fChar >= fEnd) {
455                 return false;
456             }
457         }
458         return true;
459     }
460 
skipWhiteSpace(int * indent,bool * skippedReturn)461     bool skipWhiteSpace(int* indent, bool* skippedReturn) {
462         while (' ' >= this->peek()) {
463             *indent = *skippedReturn ? *indent + 1 : 1;
464             if ('\n' == this->peek()) {
465                 *skippedReturn |= true;
466                 *indent = 0;
467             }
468             (void) this->next();
469             if (fChar >= fEnd) {
470                 return false;
471             }
472         }
473         return true;
474     }
475 
startsWith(const char * str)476     bool startsWith(const char* str) const {
477         size_t len = strlen(str);
478         ptrdiff_t lineLen = fEnd - fChar;
479         return len <= (size_t) lineLen && 0 == strncmp(str, fChar, len);
480     }
481 
482     // ignores minor white space differences
startsWith(const char * str,size_t oLen)483     bool startsWith(const char* str, size_t oLen) const {
484         size_t tIndex = 0;
485         size_t tLen = fEnd - fChar;
486         size_t oIndex = 0;
487         while (oIndex < oLen && tIndex < tLen) {
488             bool tSpace = ' ' >= fChar[tIndex];
489             bool oSpace = ' ' >= str[oIndex];
490             if (tSpace != oSpace) {
491                 break;
492             }
493             if (tSpace) {
494                 do {
495                     ++tIndex;
496                 } while (tIndex < tLen && ' ' >= fChar[tIndex]);
497                 do {
498                     ++oIndex;
499                 } while (oIndex < oLen && ' ' >= str[oIndex]);
500                 continue;
501             }
502             if (fChar[tIndex] != str[oIndex]) {
503                 break;
504             }
505             ++tIndex;
506             ++oIndex;
507         }
508         return oIndex >= oLen;
509     }
510 
strnchr(char ch,const char * end)511     const char* strnchr(char ch, const char* end) const {
512         const char* ptr = fChar;
513         while (ptr < end) {
514             if (ptr[0] == ch) {
515                 return ptr;
516             }
517             ++ptr;
518         }
519         return nullptr;
520     }
521 
strnstr(const char * match,const char * end)522     const char* strnstr(const char *match, const char* end) const {
523         size_t matchLen = strlen(match);
524         SkASSERT(matchLen > 0);
525         ptrdiff_t len = end - fChar;
526         SkASSERT(len >= 0);
527         if ((size_t) len < matchLen ) {
528             return nullptr;
529         }
530         size_t count = len - matchLen;
531         for (size_t index = 0; index <= count; index++) {
532             if (0 == strncmp(&fChar[index], match, matchLen)) {
533                 return &fChar[index];
534             }
535         }
536         return nullptr;
537     }
538 
trimmedBracketEnd(const char bracket)539     const char* trimmedBracketEnd(const char bracket) const {
540         int max = (int) (this->lineLength());
541         int index = 0;
542         while (index < max && bracket != fChar[index]) {
543             ++index;
544         }
545         SkASSERT(index < max);
546         while (index > 0 && ' ' >= fChar[index - 1]) {
547             --index;
548         }
549         return fChar + index;
550     }
551 
trimmedBracketEnd(string bracket)552     const char* trimmedBracketEnd(string bracket) const {
553         size_t max = (size_t) (this->lineLength());
554         string line(fChar, max);
555         size_t index = line.find(bracket);
556         SkASSERT(index < max);
557         while (index > 0 && ' ' >= fChar[index - 1]) {
558             --index;
559         }
560         return fChar + index;
561     }
562 
trimmedBracketNoEnd(const char bracket)563     const char* trimmedBracketNoEnd(const char bracket) const {
564         int max = (int) (fEnd - fChar);
565         int index = 0;
566         while (index < max && bracket != fChar[index]) {
567             ++index;
568         }
569         SkASSERT(index < max);
570         while (index > 0 && ' ' >= fChar[index - 1]) {
571             --index;
572         }
573         return fChar + index;
574     }
575 
trimmedLineEnd()576     const char* trimmedLineEnd() const {
577         const char* result = this->lineEnd();
578         while (result > fChar && ' ' >= result[-1]) {
579             --result;
580         }
581         return result;
582     }
583 
trimEnd()584     void trimEnd() {
585         while (fEnd > fStart && ' ' >= fEnd[-1]) {
586             --fEnd;
587         }
588     }
589 
590     // FIXME: nothing else in TextParser knows from C++ --
591     // there could be a class between TextParser and ParserCommon
592     virtual string typedefName();
593 
wordEnd()594     const char* wordEnd() const {
595         const char* end = fChar;
596         while (isalnum(end[0]) || '_' == end[0] || '-' == end[0]) {
597             ++end;
598         }
599         return end;
600     }
601 
602     string fFileName;
603     const char* fStart;
604     const char* fLine;
605     const char* fChar;
606     const char* fEnd;
607     size_t fLineCount;
608 };
609 
610 class TextParserSave {
611 public:
TextParserSave(TextParser * parser)612     TextParserSave(TextParser* parser) {
613         fParser = parser;
614         fSave.fFileName = parser->fFileName;
615         fSave.fStart = parser->fStart;
616         fSave.fLine = parser->fLine;
617         fSave.fChar = parser->fChar;
618         fSave.fEnd = parser->fEnd;
619         fSave.fLineCount = parser->fLineCount;
620     }
621 
restore()622     void restore() const {
623         fParser->fFileName = fSave.fFileName;
624         fParser->fStart = fSave.fStart;
625         fParser->fLine = fSave.fLine;
626         fParser->fChar = fSave.fChar;
627         fParser->fEnd = fSave.fEnd;
628         fParser->fLineCount = fSave.fLineCount;
629     }
630 
631 private:
632     TextParser* fParser;
633     TextParser fSave;
634 };
635 
has_nonwhitespace(string s)636 static inline bool has_nonwhitespace(string s) {
637     bool nonwhite = false;
638     for (const char& c : s) {
639         if (' ' < c) {
640             nonwhite = true;
641             break;
642         }
643     }
644     return nonwhite;
645 }
646 
trim_end(string & s)647 static inline void trim_end(string &s) {
648     s.erase(std::find_if(s.rbegin(), s.rend(),
649             std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
650 }
651 
trim_end_spaces(string & s)652 static inline void trim_end_spaces(string &s) {
653     while (s.length() > 0 && ' ' == s.back()) {
654         s.pop_back();
655     }
656 }
657 
trim_start(string & s)658 static inline void trim_start(string &s) {
659     s.erase(s.begin(), std::find_if(s.begin(), s.end(),
660             std::not1(std::ptr_fun<int, int>(std::isspace))));
661 }
662 
trim_start_end(string & s)663 static inline void trim_start_end(string& s) {
664     trim_start(s);
665     trim_end(s);
666 }
667 
trim_inline_spaces(string s)668 static inline string trim_inline_spaces(string s) {
669     bool lastSpace = false;
670     string trimmed;
671     for (const char* ptr = &s.front(); ptr <= &s.back(); ++ptr) {
672         char c = *ptr;
673         if (' ' >= c) {
674             if (!lastSpace) {
675                 trimmed += ' ';
676             }
677             lastSpace = true;
678             continue;
679         }
680         lastSpace = false;
681         trimmed += c;
682     }
683     return trimmed;
684 }
685 
686 class EscapeParser : public TextParser {
687 public:
EscapeParser(const char * start,const char * end)688     EscapeParser(const char* start, const char* end) :
689             TextParser("", start, end, 0) {
690         const char* reader = fStart;
691         fStorage = new char[end - start];
692         char* writer = fStorage;
693         while (reader < fEnd) {
694             char ch = *reader++;
695             if (ch != '\\') {
696                 *writer++ = ch;
697             } else {
698                 char ctrl = *reader++;
699                 if (ctrl == 'u') {
700                     unsigned unicode = 0;
701                     for (int i = 0; i < 4; ++i) {
702                         unicode <<= 4;
703                         SkASSERT((reader[0] >= '0' && reader[0] <= '9') ||
704                             (reader[0] >= 'A' && reader[0] <= 'F') ||
705                             (reader[0] >= 'a' && reader[0] <= 'f'));
706                         int nibble = *reader++ - '0';
707                         if (nibble > 9) {
708                             nibble = (nibble & ~('a' - 'A')) - 'A' + '9' + 1;
709                         }
710                         unicode |= nibble;
711                     }
712                     SkASSERT(unicode < 256);
713                     *writer++ = (unsigned char) unicode;
714                 } else {
715                     SkASSERT(ctrl == 'n');
716                     *writer++ = '\n';
717                 }
718             }
719         }
720         fStart = fLine = fChar = fStorage;
721         fEnd = writer;
722     }
723 
~EscapeParser()724     ~EscapeParser() override {
725         delete fStorage;
726     }
727 private:
728     char* fStorage;
729 };
730 
731 // some methods cannot be trivially parsed; look for class-name / ~ / operator
732 class MethodParser : public TextParser {
733 public:
MethodParser(string className,string fileName,const char * start,const char * end,int lineCount)734     MethodParser(string className, string fileName,
735             const char* start, const char* end, int lineCount)
736         : TextParser(fileName, start, end, lineCount)
737         , fClassName(className) {
738         size_t doubleColons = className.find_last_of("::");
739         if (string::npos != doubleColons) {
740             fLocalName = className.substr(doubleColons + 1);
741             SkASSERT(fLocalName.length() > 0);
742         }
743     }
744 
~MethodParser()745     ~MethodParser() override {}
746 
localName()747     string localName() const {
748         return fLocalName;
749     }
750 
setLocalName(string name)751     void setLocalName(string name) {
752         if (name == fClassName) {
753             fLocalName = "";
754         } else {
755             fLocalName = name;
756         }
757     }
758 
759     // returns true if close brace was skipped
skipToMethodStart()760     int skipToMethodStart() {
761         if (!fClassName.length()) {
762             return this->skipToAlphaNum();
763         }
764         int braceCount = 0;
765         while (!this->eof() && !isalnum(this->peek()) && '~' != this->peek()) {
766             braceCount += '{' == this->peek();
767             braceCount -= '}' == this->peek();
768             this->next();
769         }
770         return braceCount;
771     }
772 
773     void skipToMethodEnd(Resolvable resolvable);
774 
wordEndsWith(const char * str)775     bool wordEndsWith(const char* str) const {
776         const char* space = this->strnchr(' ', fEnd);
777         if (!space) {
778             return false;
779         }
780         size_t len = strlen(str);
781         if (space < fChar + len) {
782             return false;
783         }
784         return !strncmp(str, space - len, len);
785     }
786 
787 private:
788     string fClassName;
789     string fLocalName;
790     typedef TextParser INHERITED;
791 };
792 
793 #endif
794