Alien-SmokeQt

 view release on metacpan or  search on metacpan

generator/parser/rpp/pp-macro-expander.cpp  view on Meta::CPAN

  for(; lastValid >= 0; --lastValid)
    if(array[lastValid] != indexFromCharacter(' '))
      break;
  
  array.resize(lastValid+1);
  
  int firstValid = 0;
  for(; firstValid < array.size(); ++firstValid)
    if(array[firstValid] != indexFromCharacter(' '))
      break;
  array = array.mid(firstValid);
}

using namespace rpp;              

pp_frame::pp_frame(pp_macro* __expandingMacro, const QList<pp_actual>& __actuals)
  : depth(0)
  , expandingMacro(__expandingMacro)
  , actuals(__actuals)
{
}

pp_actual pp_macro_expander::resolve_formal(IndexedString name, Stream& input)
{
  if (!m_frame)
    return pp_actual();

  Q_ASSERT(m_frame->expandingMacro != 0);

  const QVector<IndexedString>& formals = m_frame->expandingMacro->formals;
  uint formalsSize = formals.size();

  if(name.isEmpty()) {
    Problem *problem = new Problem;
    problem->file = m_engine->currentFileNameString();
    problem->position = input.originalInputPosition();
    problem->description = "Macro error";
    m_engine->problemEncountered(problem);
    return pp_actual();
  }
  
  for (uint index = 0; index < formalsSize; ++index) {
    if (name.index() == formals[index].index()) {
      if (index < (uint)m_frame->actuals.size()) {
        return m_frame->actuals[index];
      }
      else {
        Problem *problem = new Problem;
        problem->file = m_engine->currentFileNameString();
        problem->position = input.originalInputPosition();
        problem->description = QString("Call to macro %1 missing argument number %2").arg(name.str()).arg(index);
        problem->explanation = QString("Formals: %1").arg(joinIndexVector(formals, ", "));
        m_engine->problemEncountered(problem);
      }
    }
  }

  return pp_actual();
}

#define RETURN_IF_INPUT_BROKEN    if(input.atEnd()) { qDebug() << "too early end while expanding" << macro->name.str(); return; }


pp_macro_expander::pp_macro_expander(pp* engine, pp_frame* frame, bool inHeaderSection)
  : m_engine(engine)
  , m_frame(frame)
  , m_in_header_section(inHeaderSection)
  , m_search_significant_content(false)
  , m_found_significant_content(false)
{
  if(m_in_header_section)
    m_search_significant_content = true; //Find the end of the header section
}

//A header-section ends when the first non-directive and non-comment occurs
#define check_header_section \
  if( m_search_significant_content ) \
  { \
     \
    if(m_in_header_section) { \
      m_in_header_section = false; \
      m_engine->preprocessor()->headerSectionEnded(input); \
    } \
    m_found_significant_content = true;  \
    m_search_significant_content = false; \
    if( input.atEnd() ) \
      continue; \
  } \

struct EnableMacroExpansion {
  EnableMacroExpansion(Stream& _input, const SimpleCursor& expansionPosition) : input(_input), hadMacroExpansion(_input.macroExpansion().isValid()) {
    
    if(!hadMacroExpansion)
      _input.setMacroExpansion(expansionPosition);
  }
  ~EnableMacroExpansion() {
    if(!hadMacroExpansion)
      input.setMacroExpansion(SimpleCursor::invalid());
  }
  Stream& input;
  bool hadMacroExpansion;
};

IndexedString definedIndex = IndexedString("defined");
IndexedString lineIndex = IndexedString("__LINE__");
IndexedString fileIndex = IndexedString("__FILE__");
IndexedString dateIndex = IndexedString("__DATE__");
IndexedString timeIndex= IndexedString("__TIME__");

void pp_macro_expander::operator()(Stream& input, Stream& output)
{
  skip_blanks(input, output);

  while (!input.atEnd())
  {
    if (isComment(input))
    {
      skip_comment_or_divop(input, output, true);
    }else{
      if (input == '\n')
      {

generator/parser/rpp/pp-macro-expander.cpp  view on Meta::CPAN

            output.appendString(inputPosition, convertFromByteArray(QTime::currentTime().toString("hh:mm:ss").toUtf8()));
          else
            output.appendString(inputPosition, name);
          continue;
        }
        
        EnableMacroExpansion enable(output, input.inputPosition()); //Configure the output-stream so it marks all stored input-positions as transformed through a macro

          if (macro->definition.size()) {
            macro->hidden = true;

            pp_macro_expander expand_macro(m_engine);
            ///@todo UGLY conversion
            Stream ms((uint*)macro->definition.constData(), macro->definition.size(), Anchor(input.inputPosition(), true));
            ms.setOriginalInputPosition(input.originalInputPosition());
            PreprocessedContents expanded;
            {
              Stream es(&expanded);
              expand_macro(ms, es);
            }

            if (!expanded.isEmpty())
            {
              Stream es(&expanded, Anchor(input.inputPosition(), true));
              es.setOriginalInputPosition(input.originalInputPosition());
              skip_whitespaces(es, devnull());
              IndexedString identifier = IndexedString::fromIndex( skip_identifier(es) );

              output.appendString(Anchor(input.inputPosition(), true), expanded);
              output << ' '; //Prevent implicit token merging
            }

            macro->hidden = false;
          }
        }else if(input == '(') {

        //Eventually execute a function-macro
          
        IndexedString previous = IndexedString::fromIndex(indexFromCharacter(' ')); //Previous already has been expanded
        uint stepsBack = 0;
        while(isCharacter(previous.index()) && characterFromIndex(previous.index()) == ' ' && output.peekLastOutput(stepsBack)) {
          previous = IndexedString::fromIndex(output.peekLastOutput(stepsBack));
          ++stepsBack;
        }
        
        pp_macro* macro = m_engine->environment()->retrieveMacro(previous, false);
        
        if(!macro || !macro->function_like || !macro->defined || macro->hidden) {
          output << input;
          ++input;
          continue;
        }
        
        //In case expansion fails, we can skip back to this position
        int openingPosition = input.offset();
        Anchor openingPositionCursor = input.inputPosition();
        
        QList<pp_actual> actuals;
        ++input; // skip '('
        
        RETURN_IF_INPUT_BROKEN

        pp_macro_expander expand_actual(m_engine, m_frame);

        {
          PreprocessedContents actualText;
          skip_whitespaces(input, devnull());
          Anchor actualStart = input.inputPosition();
          {
            Stream as(&actualText);
            skip_argument_variadics(actuals, macro, input, as);
          }
          trim(actualText);

          pp_actual newActual;
          {
            PreprocessedContents newActualText;
            Stream as(&actualText, actualStart);
            as.setOriginalInputPosition(input.originalInputPosition());

            rpp::LocationTable table;
            table.anchor(0, actualStart, 0);
            Stream nas(&newActualText, actualStart, &table);
            expand_actual(as, nas);
            
            table.splitByAnchors(newActualText, actualStart, newActual.text, newActual.inputPosition);
          }
          newActual.forceValid = true;
          
          actuals.append(newActual);
        }

        // TODO: why separate from the above?
        while (!input.atEnd() && input == ',')
        {
          ++input; // skip ','
          
          RETURN_IF_INPUT_BROKEN

          {
            PreprocessedContents actualText;
            skip_whitespaces(input, devnull());
            Anchor actualStart = input.inputPosition();
            {
              Stream as(&actualText);
              skip_argument_variadics(actuals, macro, input, as);
            }
            trim(actualText);

            pp_actual newActual;
            {
              PreprocessedContents newActualText;
              Stream as(&actualText, actualStart);
              as.setOriginalInputPosition(input.originalInputPosition());

              PreprocessedContents actualText;
              rpp::LocationTable table;
              table.anchor(0, actualStart, 0);
              Stream nas(&newActualText, actualStart, &table);
              expand_actual(as, nas);
              
              table.splitByAnchors(newActualText, actualStart, newActual.text, newActual.inputPosition);
            }
            newActual.forceValid = true;
            actuals.append(newActual);
          }
        }

        if( input != ')' ) {
          //Failed to expand the macro. Output the macro name and continue normal
          //processing behind it.(Code completion depends on this behavior when expanding
          //incomplete input-lines)
          input.seek(openingPosition);
          input.setInputPosition(openingPositionCursor);
          //Move one character into the output, so we don't get an endless loop
          output << input;
          ++input;
          
          continue;
        }
        
        //Remove the name of the called macro
        while(stepsBack) {
          --stepsBack;
          output.popLastOutput();
        }
        
        //Q_ASSERT(!input.atEnd() && input == ')');

        ++input; // skip ')'
        
#if 0 // ### enable me
        assert ((macro->variadics && macro->formals.size () >= actuals.size ())
                    || macro->formals.size() == actuals.size());
#endif
        EnableMacroExpansion enable(output, input.inputPosition()); //Configure the output-stream so it marks all stored input-positions as transformed through a macro

        pp_frame frame(macro, actuals);
        if(m_frame)
          frame.depth = m_frame->depth + 1;
        
        if(frame.depth >= maxMacroExpansionDepth) 
        {
          qDebug() << "reached maximum macro-expansion depth while expanding" << macro->name.str();
          RETURN_IF_INPUT_BROKEN
          
          output << input;
          ++input;
        }else{
          pp_macro_expander expand_macro(m_engine, &frame);
          macro->hidden = true;
          ///@todo UGLY conversion
          Stream ms((uint*)macro->definition.constData(), macro->definition.size(), Anchor(input.inputPosition(), true));
          ms.setOriginalInputPosition(input.originalInputPosition());
          expand_macro(ms, output);
          output << ' '; //Prevent implicit token merging
          macro->hidden = false;
        }
      } else {
        output << input;
        ++input;
      }
    }

  }
}

void pp_macro_expander::skip_argument_variadics (const QList<pp_actual>& __actuals, pp_macro *__macro, Stream& input, Stream& output)
{
  int first;

  do {
    first = input.offset();
    skip_argument(input, output);

  } while ( __macro->variadics
            && first != input.offset()
            && !input.atEnd()
            && input == '.'
            && (__actuals.size() + 1) == (int)__macro->formals.size());
}



( run in 0.471 second using v1.01-cache-2.11-cpan-13bb782fe5a )