tools/porting/src/rpptreeevaluator.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2001-2004 Roberto Raggi
       
     4 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     5 ** All rights reserved.
       
     6 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     7 **
       
     8 ** This file is part of the qt3to4 porting application of the Qt Toolkit.
       
     9 **
       
    10 ** $QT_BEGIN_LICENSE:LGPL$
       
    11 ** No Commercial Usage
       
    12 ** This file contains pre-release code and may not be distributed.
       
    13 ** You may use this file in accordance with the terms and conditions
       
    14 ** contained in the Technology Preview License Agreement accompanying
       
    15 ** this package.
       
    16 **
       
    17 ** GNU Lesser General Public License Usage
       
    18 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    19 ** General Public License version 2.1 as published by the Free Software
       
    20 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    21 ** packaging of this file.  Please review the following information to
       
    22 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    24 **
       
    25 ** In addition, as a special exception, Nokia gives you certain additional
       
    26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    28 **
       
    29 ** If you have questions regarding the use of this file, please contact
       
    30 ** Nokia at qt-info@nokia.com.
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 **
       
    39 ** $QT_END_LICENSE$
       
    40 **
       
    41 ****************************************************************************/
       
    42 
       
    43 #include "rpptreeevaluator.h"
       
    44 #include <QChar>
       
    45 #include <QtDebug>
       
    46 
       
    47 QT_BEGIN_NAMESPACE
       
    48 
       
    49 using namespace TokenEngine;
       
    50 namespace Rpp {
       
    51 
       
    52 RppTreeEvaluator::RppTreeEvaluator()
       
    53 {
       
    54     QByteArray text(" ");
       
    55     TokenEngine::Token token;
       
    56     token.start = 0;
       
    57     token.length = 1;
       
    58     QVector<TokenEngine::Token> tokenList;
       
    59     tokenList.append(token);
       
    60     TokenContainer newLineContainer(text, tokenList, new TokenEngine::GeneratedInfo());
       
    61     newlineSection= new TokenSection(newLineContainer, 0, 1);
       
    62 }
       
    63 
       
    64 RppTreeEvaluator::~RppTreeEvaluator()
       
    65 {
       
    66     delete newlineSection;
       
    67 }
       
    68 
       
    69 TokenSectionSequence RppTreeEvaluator::evaluate(const Source *source,
       
    70                                                 DefineMap *activeDefinitions)
       
    71 {
       
    72     m_tokenSections.clear();
       
    73     m_activeDefinitions = activeDefinitions;
       
    74     evaluateSource(source);
       
    75     return TokenSectionSequence(m_tokenSections);
       
    76 }
       
    77 
       
    78 void RppTreeEvaluator::evaluateText(const Text *textLine)
       
    79 {
       
    80     const int numTokens = textLine->count();
       
    81     const TokenContainer tokenContainer = textLine->text().tokenContainer(0);
       
    82 
       
    83     int t = 0;
       
    84     int startTokenRun = 0;
       
    85     while(t < numTokens) {
       
    86         const Token *currentToken = textLine->token(t);
       
    87         int currentContainerIndex = currentToken->index();
       
    88         //handle macro replacements
       
    89         if(currentToken->toIdToken()) {
       
    90             const int tokenIndex = currentToken->index();
       
    91             const QByteArray tokenText = tokenContainer.tempText(tokenIndex);
       
    92             if(m_activeDefinitions->contains(tokenText)) {
       
    93                 //crate section
       
    94                 TokenSection section(tokenContainer, textLine->token(startTokenRun)->index(), t - startTokenRun);
       
    95                 m_tokenSections.append(section);
       
    96                 //evaluate macro
       
    97                 const int oldContainerIndex = currentContainerIndex;
       
    98                 TokenContainer evaluatedText = evaluateMacro(tokenContainer, currentContainerIndex);
       
    99                 TokenSection evalSection(evaluatedText, 0, evaluatedText.count());
       
   100                 m_tokenSections.append(evalSection);
       
   101                 t += currentContainerIndex - oldContainerIndex;
       
   102                 startTokenRun = t;
       
   103             }
       
   104             ++t;
       
   105             continue;
       
   106         }
       
   107 
       
   108         //handle comments
       
   109         if(currentToken->toLineComment() || currentToken->toMultiLineComment()) {
       
   110             //create section
       
   111             TokenSection section(tokenContainer, textLine->token(startTokenRun)->index(), t - startTokenRun );
       
   112             m_tokenSections.append(section);
       
   113             t++; //skip comment
       
   114             startTokenRun = t;
       
   115             t++;
       
   116             continue;
       
   117         }
       
   118 
       
   119         // handle escaped newlines
       
   120 		if (currentContainerIndex + 1 < numTokens) {
       
   121             const TokenTempRef tokenRef1 = tokenContainer.tokenTempRef(currentContainerIndex);
       
   122             const TokenTempRef tokenRef2 = tokenContainer.tokenTempRef(currentContainerIndex + 1);
       
   123 			// This is i slight hack. We want to check if the next token is a newline token,
       
   124 			// but since we don't have any lexical info at this point we just check if it starts
       
   125 			// with \r or \n
       
   126 			if (tokenRef1.at(0) == '\\' && (tokenRef2.at(0) == '\n' || tokenRef2.at(0) == '\r')) {
       
   127 				//create section
       
   128                 TokenSection section(tokenContainer, textLine->token(startTokenRun)->index(), t - startTokenRun );
       
   129                 m_tokenSections.append(section);
       
   130                 t += 2;
       
   131                 startTokenRun = t;
       
   132                 t++;
       
   133                 continue;
       
   134             }
       
   135         }
       
   136 
       
   137         t++;
       
   138     }
       
   139     //round up any tokens at the end and put them in a section
       
   140     if(t - startTokenRun > 1) {
       
   141         TokenSection section(tokenContainer, textLine->token(startTokenRun)->index(), t - startTokenRun );
       
   142         m_tokenSections.append(section);
       
   143     }
       
   144 
       
   145     m_tokenSections.append(*newlineSection);
       
   146 }
       
   147 
       
   148 /*
       
   149     Evaluates and ifsection by selecting which one of the if-elif-else
       
   150     groups and then evaling that.
       
   151 */
       
   152 void RppTreeEvaluator::evaluateIfSection(const IfSection *ifSection)
       
   153 {
       
   154     ConditionalDirective *ifGroup = ifSection->ifGroup();
       
   155     if(evaluateCondition(ifGroup)) {
       
   156         evaluateConditionalDirective(ifGroup);
       
   157         return;
       
   158     }
       
   159 
       
   160     QVector<ConditionalDirective *> elifGroups = ifSection->elifGroups();
       
   161     foreach(ConditionalDirective *elifGroup, elifGroups) {
       
   162         if(evaluateCondition(elifGroup)) {
       
   163             evaluateConditionalDirective(elifGroup);
       
   164             return;
       
   165         }
       
   166     }
       
   167 
       
   168     ConditionalDirective *elseGroup = ifSection->elseGroup();
       
   169     if(elseGroup)
       
   170         evaluateConditionalDirective(elseGroup);
       
   171 }
       
   172 
       
   173 /*
       
   174     Evaluate an IncludeDirective by evaluating the Source for the included
       
   175     file. The source is found by emitting the includeCallback signal, which
       
   176     must be handled outside RppTreeEvaluator.
       
   177 */
       
   178 void RppTreeEvaluator::evaluateIncludeDirective(const IncludeDirective *directive)
       
   179 {
       
   180     Source *currentSource = getParentSource(directive);
       
   181     IncludeType includeType = includeTypeFromDirective(directive);
       
   182     Source *newSource = 0;
       
   183     emit includeCallback(newSource, currentSource, QString::fromLatin1(directive->filename().constData()), includeType);
       
   184     Q_ASSERT(newSource);    // If you get an assert here you probably
       
   185                             // forgot to connect to the includeCallback signal
       
   186     evaluateSource(newSource);
       
   187 }
       
   188 
       
   189 void RppTreeEvaluator::evaluateDefineDirective(const DefineDirective *directive)
       
   190 {
       
   191     m_tokenSections.append(*newlineSection);
       
   192     m_activeDefinitions->insert(directive->identifier().fullText(), directive);
       
   193 }
       
   194 
       
   195 void RppTreeEvaluator::evaluateUndefDirective(const UndefDirective *directive)
       
   196 {
       
   197     m_tokenSections.append(*newlineSection);
       
   198     const QByteArray text = directive->identifier().fullText();
       
   199     m_activeDefinitions->remove(text);
       
   200 }
       
   201 
       
   202 /*
       
   203     Evaluate the truth-value of an conditionalDirective
       
   204 */
       
   205 bool RppTreeEvaluator::evaluateCondition(const ConditionalDirective *conditionalDirective)
       
   206 {
       
   207     if (IfDirective *ifDirective = conditionalDirective->toIfDirective())
       
   208         return (evaluateExpression(ifDirective->expression()) != 0);
       
   209     if (ElifDirective *elifDirective = conditionalDirective->toElifDirective())
       
   210         return (evaluateExpression(elifDirective->expression()) != 0);
       
   211     if (IfdefDirective *ifdefDirective = conditionalDirective->toIfdefDirective())
       
   212         return m_activeDefinitions->contains(ifdefDirective->identifier().fullText());
       
   213     if (IfndefDirective *ifndefDirective = conditionalDirective->toIfndefDirective())
       
   214         return !m_activeDefinitions->contains(ifndefDirective->identifier().fullText());
       
   215     else
       
   216         return false; //error!
       
   217 }
       
   218 
       
   219 /*
       
   220     Recursively evaluates an Expression
       
   221 */
       
   222 int RppTreeEvaluator::evaluateExpression(Expression *expression)
       
   223 {
       
   224     if (IntLiteral *e = expression->toIntLiteral()) {
       
   225         return e->value();
       
   226     } else if (StringLiteral *e = expression->toStringLiteral()) {
       
   227         return e->value().size();
       
   228     } else if (MacroReference *e = expression->toMacroReference()) {
       
   229        switch(e->type()) {
       
   230            case MacroReference::DefinedRef: {
       
   231                return m_activeDefinitions->contains(e->name().fullText()) ? 1 : 0;
       
   232            } case MacroReference::ValueRef: {
       
   233                const QByteArray identifier = e->name().fullText();
       
   234                if (m_activeDefinitions->contains(identifier)) {
       
   235                    int token = e->name().containerIndex(0);
       
   236                    TokenContainer value = evaluateMacro(e->name().tokenContainer(token), token);
       
   237                    return QString(QLatin1String(value.fullText())).toInt(0, 0);
       
   238                } else {
       
   239                    return 0; // error
       
   240                }
       
   241            }
       
   242            default: Q_ASSERT(0);
       
   243         }
       
   244     } else if (MacroFunctionReference *e = expression->toMacroFunctionReference()) {
       
   245         Q_UNUSED(e);
       
   246         //TODO handle MacroFunctionReference
       
   247 //        DefineDirective *def = e->findDefinition(e->name());
       
   248 //        Q_ASSERT(def->toMacroFunctionDefinition());
       
   249 //        qWarning("not implemented yet");
       
   250         return 0;
       
   251     } else if (UnaryExpression *e = expression->toUnaryExpression()) {
       
   252         int result = evaluateExpression(e->expression());
       
   253         switch (e->op()) {
       
   254             case '+': return + result;
       
   255             case '-': return - result;
       
   256             case '!': return ! result;
       
   257             case '~': return ~ result;
       
   258             default:  Q_ASSERT(0);
       
   259         }
       
   260     } else if (BinaryExpression *e = expression->toBinaryExpression()) {
       
   261         int v1 = evaluateExpression(e->leftExpression());
       
   262         int v2 = evaluateExpression(e->rightExpression());
       
   263 
       
   264         switch (e->op()) {
       
   265             case '/': { return v2 ? v1 / v2 : 0; } //avoid division by zero
       
   266             case '*':                  return v1 * v2;
       
   267             case '%': { return v2 ? v1 % v2 : 0; } //avoid modulus by zero
       
   268             case '+':                  return v1 + v2;
       
   269             case '-':                  return v1 - v2;
       
   270             case '<':                  return v1 < v2;
       
   271             case '>':                  return v1 > v2;
       
   272             case '&':                  return v1 & v2;
       
   273             case '^':                  return v1 ^ v2;
       
   274             case '|':                  return v1 | v2;
       
   275             case Expression::LtEqOp:   return v1 <= v2;
       
   276             case Expression::GtEqOp:   return v1 >= v2;
       
   277             case Expression::EqOp:     return v1 == v2;
       
   278             case Expression::NotEqOp:  return v1 != v2;
       
   279             case Expression::AndOp:    return v1 && v2;
       
   280             case Expression::OrOp:     return v1 || v2;
       
   281             case Expression::LShiftOp: return v1 << v2;
       
   282             case Expression::RShiftOp: return v1 >> v2;
       
   283             default:    Q_ASSERT(0);
       
   284         }
       
   285 
       
   286     } else if ( ConditionalExpression *e = expression->toConditionalExpression()){
       
   287         return e->condition() ? evaluateExpression(e->leftExpression()) : evaluateExpression(e->rightExpression());
       
   288     }
       
   289     return 0;
       
   290 }
       
   291 /*
       
   292     Expands a macro at index identiferTokenIndex in tokenContainer. Returns
       
   293     the expanded macro text, and updates identiferTokenIndex to point after
       
   294     the last token consumed.
       
   295 
       
   296     Given the construct 'FN(a)', the '(a)' part will be consumed if FN is
       
   297     defined to be a macro function, but not if it is an ordenary macro.
       
   298 */
       
   299 TokenContainer RppTreeEvaluator::evaluateMacro(TokenContainer tokenContainer, int &identiferTokenIndex)
       
   300 {
       
   301     QByteArray identifierText = tokenContainer.text(identiferTokenIndex);
       
   302     if(!m_activeDefinitions->contains(identifierText))
       
   303         return TokenContainer();
       
   304 
       
   305     const Rpp::DefineDirective *directive = m_activeDefinitions->value(identifierText);
       
   306     Q_ASSERT(directive);
       
   307 
       
   308     // To prevent infinite recursive macro expansions, the skip set contains
       
   309     // a set of identifers already seen.
       
   310     QSet<QByteArray> skip;
       
   311 
       
   312     if(directive->toMacroDefinition()) {
       
   313         ++identiferTokenIndex;
       
   314         QVector<TokenEngine::Token> tokenList;
       
   315         tokenList.append(TokenEngine::Token(0, identifierText.count()));
       
   316         return evaluateMacroInternal(skip, TokenContainer(identifierText, tokenList));
       
   317     } else if (Rpp::MacroFunctionDefinition *macro = directive->toMacroFunctionDefinition()) {
       
   318         MacroFunctionParser macroFunctionParser(tokenContainer, identiferTokenIndex);
       
   319         if (macroFunctionParser.isValid() && macro->parameters().count() ==  macroFunctionParser.argumentCount()) {
       
   320             TokenContainer macroFunctionContainer =
       
   321                 TokenEngine::copy(tokenContainer, identiferTokenIndex, macroFunctionParser.tokenCount());
       
   322             identiferTokenIndex += macroFunctionParser.tokenCount();
       
   323             return evaluateMacroInternal(skip, macroFunctionContainer);
       
   324         } else {
       
   325             // Error case, such as calling a macro function with the wrong number of parameters,
       
   326             // or calling a macro function witout a parameter list.
       
   327             return TokenEngine::copy(tokenContainer, identiferTokenIndex++, 1);
       
   328         }
       
   329     }
       
   330     return TokenContainer();
       
   331 }
       
   332 
       
   333 /*
       
   334     Recursively expands all macroes in macroInvokeTokens, returns a
       
   335     TokenContainer with the new tokens.
       
   336 */
       
   337 TokenEngine::TokenContainer RppTreeEvaluator::evaluateMacroInternal(QSet<QByteArray> skip, TokenEngine::TokenContainer macroInvokeTokens)
       
   338 {
       
   339     bool changed = false;
       
   340     QByteArray tokenText;
       
   341     QVector<TokenEngine::Token> tokenList;
       
   342     const int numTokens = macroInvokeTokens.count();
       
   343 
       
   344     for (int t = 0; t < numTokens; ++t) {
       
   345         const QByteArray identifierText = macroInvokeTokens.text(t);
       
   346 
       
   347         // if the current token text is not a part of a macro definition we just copy it.
       
   348         if (!m_activeDefinitions->contains(identifierText)) {
       
   349             tokenList.append(TokenEngine::Token(tokenText.count(), identifierText.count()));
       
   350             tokenText.append(identifierText);
       
   351             continue;
       
   352         }
       
   353 
       
   354         // If the token text is in the skip list we copy it.
       
   355          if (skip.contains(identifierText)) {
       
   356             tokenList.append(TokenEngine::Token(tokenText.count(), identifierText.count()));
       
   357             tokenText.append(identifierText);
       
   358             continue;
       
   359         }
       
   360 
       
   361         skip.insert(identifierText);
       
   362         changed = true;
       
   363         const Rpp::DefineDirective *directive = m_activeDefinitions->value(identifierText);
       
   364         Q_ASSERT(directive);
       
   365         // if it is a macro, we copy in the replacement list.
       
   366         if (Rpp::MacroDefinition *macro = directive->toMacroDefinition()) {
       
   367             TokenList replacementList = macro->replacementList();
       
   368             TokenEngine::copy(tokenText, tokenList, replacementList, 0, replacementList.count());
       
   369 
       
   370             // To avoid infinite loops, set changed to false if the replacement
       
   371             // text is identical to the identifier text.
       
   372             if (replacementList.fullText().simplified() == identifierText.simplified())
       
   373                 changed = false;
       
   374         } else if (Rpp::MacroFunctionDefinition *macro = directive->toMacroFunctionDefinition()) {
       
   375             TokenList replacementList = macro->replacementList();
       
   376             TokenList paramenterList =  macro->parameters();
       
   377 
       
   378             MacroFunctionParser macroFunctionParser(macroInvokeTokens, t);
       
   379             if (macroFunctionParser.isValid() && macro->parameters().count() == macroFunctionParser.argumentCount()) {
       
   380                 t += macroFunctionParser.tokenCount();
       
   381                 // For each token in the replacement list: If the token matches a
       
   382                 // token in the parameter list, replace it with the
       
   383                 // corresponding argument tokens from the argument list.
       
   384                 for (int replacementToken = 0; replacementToken < replacementList.count(); ++replacementToken) {
       
   385                     const QByteArray replacementTokenText = replacementList.text(replacementToken);
       
   386                     bool replaced = false;
       
   387                     for (int parameterToken = 0; parameterToken < paramenterList.count(); ++parameterToken) {
       
   388                         const QByteArray parameterTokenText = paramenterList.text(parameterToken);
       
   389                         if (parameterTokenText == replacementTokenText) {
       
   390                             TokenSection argumentTokenSection = macroFunctionParser.argument(parameterToken);
       
   391                             TokenEngine::copy(tokenText, tokenList, argumentTokenSection, 0, argumentTokenSection.count());
       
   392                             replaced = true;
       
   393                             break;
       
   394                         }
       
   395                     }
       
   396                     if (! replaced) {
       
   397                         TokenEngine::copy(tokenText, tokenList, replacementList, replacementToken, 1);
       
   398                     }
       
   399                 }
       
   400             }
       
   401         }
       
   402     }
       
   403     if (!changed)
       
   404         return macroInvokeTokens;
       
   405     return evaluateMacroInternal(skip, TokenContainer(tokenText, tokenList));
       
   406 }
       
   407 
       
   408 TokenContainer RppTreeEvaluator::cloneTokenList(const TokenList &list)
       
   409 {
       
   410     QByteArray text;
       
   411     QVector<TokenEngine::Token> tokens;
       
   412     int index = 0;
       
   413     for (int t = 0; t<list.count(); ++t) {
       
   414         const QByteArray tokenText = list.text(t);
       
   415         const int textLength = tokenText.count();
       
   416         text += tokenText;
       
   417         TokenEngine::Token token;
       
   418         token.start = index;
       
   419         token.length = textLength;
       
   420         tokens.append(token);
       
   421         index += textLength;
       
   422     }
       
   423     TokenContainer container(text, tokens, new GeneratedInfo());
       
   424     return container;
       
   425 }
       
   426 
       
   427 /*
       
   428     Returns the parent Source for a given item.
       
   429 */
       
   430 Source *RppTreeEvaluator::getParentSource(const Item *item) const
       
   431 {
       
   432     Q_ASSERT(item);
       
   433     while(item->toSource() == 0) {
       
   434         item = item->parent();
       
   435         Q_ASSERT(item);
       
   436     }
       
   437 
       
   438     return item->toSource();
       
   439 }
       
   440 /*
       
   441     We have two IncludeType enums, one in IncludeDirective and one in
       
   442     RppTreeEvaluator. This function translates between them.
       
   443 */
       
   444 RppTreeEvaluator::IncludeType RppTreeEvaluator::includeTypeFromDirective(
       
   445                     const IncludeDirective *includeDirective) const
       
   446 {
       
   447     if(includeDirective->includeType() == IncludeDirective::QuoteInclude)
       
   448         return QuoteInclude;
       
   449     else
       
   450         return AngleBracketInclude;
       
   451 }
       
   452 
       
   453 /*
       
   454     The MacrofunctionParser class is used to parse a macro function call (not
       
   455     a macro function definition.)
       
   456 
       
   457     startToken should give the token index for the identifier token for the macro function.
       
   458 */
       
   459 MacroFunctionParser::MacroFunctionParser(const TokenEngine::TokenContainer &tokenContainer, int startToken)
       
   460 :m_tokenContainer(tokenContainer)
       
   461 ,m_startToken(startToken)
       
   462 ,m_numTokens(0)
       
   463 ,m_valid(false)
       
   464 {
       
   465     int tokenIndex = startToken;
       
   466     ++tokenIndex; //skip identifier token
       
   467     int parenthesisCount = 0;
       
   468     int currentArgumentStartToken = tokenIndex;
       
   469 
       
   470     // Parse argument tokens, add arguments to the m_arguments list.
       
   471     // Arguments may consist of multiple tokens. Parenthesis in arguments
       
   472     // are allowed, as long as they match. Inside a pair of argument
       
   473     // parenthesis, ',' no longer signals a new argument. For example,
       
   474     // FN((a,b)) is legal and contains one argument.
       
   475     while(tokenIndex < tokenContainer.count()) {
       
   476         QByteArray currentText = tokenContainer.text(tokenIndex);
       
   477         ++tokenIndex;
       
   478         if (currentText == "(") {
       
   479             ++parenthesisCount;
       
   480             if (parenthesisCount == 1) {
       
   481                 // first parenthesis
       
   482                 currentArgumentStartToken = tokenIndex;
       
   483                 continue;
       
   484             }
       
   485         }
       
   486         if (currentText == ")") {
       
   487             --parenthesisCount;
       
   488             if (parenthesisCount == 0) {
       
   489                 //end of argument
       
   490                 m_arguments.append(TokenSection(tokenContainer, currentArgumentStartToken, tokenIndex - currentArgumentStartToken - 1));
       
   491                 currentArgumentStartToken = tokenIndex;
       
   492                 //end of argument list
       
   493                 break;
       
   494             }
       
   495         }
       
   496         if (currentText == "," && parenthesisCount == 1) {
       
   497             //end of argument
       
   498             m_arguments.append(TokenSection(tokenContainer, currentArgumentStartToken, tokenIndex - currentArgumentStartToken - 1));
       
   499             currentArgumentStartToken = tokenIndex;
       
   500             continue;
       
   501         }
       
   502 
       
   503         if (QChar::fromLatin1(currentText.at(0)).isSpace()) {
       
   504             continue;
       
   505         }
       
   506 
       
   507         // If we get here without having seen a paranthesis we have a syntax
       
   508         // error in the macro function call.
       
   509         if (parenthesisCount == 0) {
       
   510             parenthesisCount = -1;
       
   511             break;
       
   512         }
       
   513     }
       
   514     m_numTokens = tokenIndex - startToken;
       
   515     m_valid = (parenthesisCount == 0);
       
   516 }
       
   517 
       
   518 /*
       
   519     Returns true if the MacroFunctionParser contains a valid macro function
       
   520 */
       
   521 bool MacroFunctionParser::isValid()
       
   522 {
       
   523     return m_valid;
       
   524 }
       
   525 
       
   526 /*
       
   527     Returns the number of tokens in the tokenContainer that is covered by
       
   528     the macro function.
       
   529 */
       
   530 int MacroFunctionParser::tokenCount()
       
   531 {
       
   532     return m_numTokens;
       
   533 }
       
   534 
       
   535 /*
       
   536     Returns the number of arguments for the macro function.
       
   537 */
       
   538 int MacroFunctionParser::argumentCount()
       
   539 {
       
   540     return m_arguments.count();
       
   541 }
       
   542 
       
   543 /*
       
   544     Returns the tokens for the argument given by argumentIndex.
       
   545 */
       
   546 TokenSection MacroFunctionParser::argument(int argumentIndex)
       
   547 {
       
   548     Q_ASSERT(argumentIndex < m_arguments.count());
       
   549     return m_arguments.at(argumentIndex);
       
   550 }
       
   551 
       
   552 } //namespace Rpp
       
   553 
       
   554 QT_END_NAMESPACE