Home | History | Annotate | Download | only in api
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <iostream>
     18 #include <sstream>
     19 
     20 #include "Scanner.h"
     21 #include "Specification.h"
     22 #include "Utilities.h"
     23 
     24 using namespace std;
     25 
     26 // Maximum of errors we'll report before bailing out.
     27 const int MAX_ERRORS = 10;
     28 
     29 Scanner::Scanner(const string& fileName, FILE* file)
     30     : mFileName(fileName), mFile(file), mLineNumber(0), mTagConsumed(true), mErrorCount(0) {
     31 }
     32 
     33 bool Scanner::atEnd() {
     34     return (mTagConsumed && feof(mFile)) || mErrorCount > MAX_ERRORS;
     35 }
     36 
     37 int Scanner::getChar() {
     38     int c = fgetc(mFile);
     39     if (c == '\n') {
     40         mLineNumber++;
     41     }
     42     return c;
     43 }
     44 
     45 void Scanner::readUpTo(char delimiter, string* segment) {
     46     for (;;) {
     47         int c = getChar();
     48         if (c == EOF || c == '\n') {
     49             break;
     50         }
     51         segment->push_back((char)c);
     52         if (c == delimiter) {
     53             break;
     54         }
     55     }
     56 }
     57 
     58 void Scanner::readRestOfLine(string* segment) {
     59     for (;;) {
     60         int c = getChar();
     61         if (c == EOF || c == '\n') {
     62             return;
     63         }
     64         segment->push_back((char)c);
     65     }
     66 }
     67 
     68 bool Scanner::getNextEntry() {
     69     mTag.clear();
     70     mValue.clear();
     71     for (;;) {
     72         int c = getChar();
     73         if (c == EOF) {
     74             return false;
     75         }
     76         if (c == '#') {
     77             // Skip the comment
     78             string comment;
     79             readRestOfLine(&comment);
     80             continue;
     81         }
     82         if (c == ' ') {
     83             readRestOfLine(&mValue);
     84             break;
     85         } else if (c == '\n') {
     86             break;
     87         } else {
     88             mTag = c;
     89             readUpTo(':', &mTag);
     90             readRestOfLine(&mValue);
     91             trimSpaces(&mValue);
     92             break;
     93         }
     94     }
     95     return true;
     96 }
     97 
     98 ostream& Scanner::error() {
     99     return error(mLineNumber);
    100 }
    101 
    102 ostream& Scanner::error(int lineNumber) {
    103     if (++mErrorCount <= MAX_ERRORS) {
    104         cerr << mFileName << ":" << lineNumber << ": error: ";
    105     }
    106     return cerr;
    107 }
    108 
    109 void Scanner::skipBlankEntries() {
    110     while (findOptionalTag("")) {
    111         if (!mValue.empty()) {
    112             error() << "Unexpected: \" " << mValue << "\".\n";
    113         }
    114     }
    115 }
    116 
    117 bool Scanner::findTag(const char* tag) {
    118     bool found = findOptionalTag(tag);
    119     if (!found) {
    120         error() << "Found \"" << mTag << "\" while looking for \"" << tag << "\".\n";
    121     }
    122     mTagConsumed = true;
    123     return found;
    124 }
    125 
    126 bool Scanner::findOptionalTag(const char* tag) {
    127     if (mTagConsumed) {
    128         if (!getNextEntry()) {
    129             return false;
    130         }
    131     }
    132     mTagConsumed = (mTag == tag);
    133     return mTagConsumed;
    134 }
    135 
    136 void Scanner::skipUntilTag(const char* tag) {
    137     while(!findOptionalTag(tag)) {
    138         mTagConsumed = true;
    139     }
    140 }
    141 
    142 void Scanner::checkNoValue() {
    143     if (!mValue.empty()) {
    144         error() << "Did not expect \"" << mValue << "\" after \"" << mTag << "\".\n";
    145     }
    146 }
    147 
    148 void Scanner::parseDocumentation(string* s, string* documentation) {
    149     size_t docStart = s->find(", \"");
    150     if (docStart == string::npos) {
    151         documentation->erase();
    152     } else {
    153         size_t first = docStart + 3;
    154         size_t last = s->find('\"', first);
    155         if (last == string::npos) {
    156             error() << "Missing closing double quote\n";
    157         }
    158         *documentation = s->substr(first, last - first);
    159         s->erase(docStart);
    160     }
    161 }
    162 
    163 ParameterEntry* Scanner::parseArgString(bool isReturn) {
    164     string s = mValue;
    165     ParameterEntry* p = new ParameterEntry();
    166     parseDocumentation(&s, &p->documentation);
    167 
    168     size_t optionStart = s.find(", ");
    169     if (optionStart != string::npos) {
    170         p->testOption = s.substr(optionStart + 2);
    171         s.erase(optionStart);
    172     }
    173 
    174     trimSpaces(&s);
    175     if (!isReturn) {
    176         size_t nameStart = s.rfind(' ');
    177         if (nameStart == string::npos) {
    178             if (s == "...") {
    179                 p->name = s;
    180                 p->type = s;
    181                 p->lineNumber = mLineNumber;
    182                 return p;
    183             } else {
    184                 error() << "Missing variable name\n";
    185             }
    186         } else {
    187             p->name = s.substr(nameStart + 1);
    188             s.erase(nameStart);
    189             if (p->name.find('*') != string::npos) {
    190                 error() << "The '*' should be attached to the type\n";
    191             }
    192         }
    193     }
    194 
    195     if (s == "void" && !isReturn) {
    196         error() << "void is only allowed for ret:\n";
    197     }
    198     p->type = s;
    199     p->lineNumber = mLineNumber;
    200     return p;
    201 }
    202