bool ScriptDocLexer::ConsumePropertyTag()
{
	bool toss;

	if (!SkipWhitespaces( toss ))		return false;
	if (!fLexerInput->HasMoreChars())	return false;

	VString typeList, name, description;
	bool isOptional, bDoFurtherProcessing;

	// Look for the optional property type(s)
	if (ConsumeTypes(typeList, bDoFurtherProcessing))
		if (!SkipWhitespaces( toss )) return false;

	// Look for the required property name.
	if (!bDoFurtherProcessing) return false;
	if (!ConsumeName( name, isOptional, bDoFurtherProcessing )) return false;

	// Now we can find the optional property description
	if (bDoFurtherProcessing)
		ConsumeComment( description );

	fLastElement = new PropertyElement( typeList, name, description );
	return true;	
}
bool ScriptDocLexer::ConsumeExceptionTag()
{
	// The exception tag takes the form: @exception {name} description, and we've already
	// handled the @exception clause.  So we want to skip over whitespace and look for the
	// {name} clause next.
	UniChar ch;
	bool toss;
	if (!SkipWhitespaces( toss ))		return false;
	if (!fLexerInput->HasMoreChars())	return false;

	// We expect the next character to be an open curly bracket.
	if (CHAR_LEFT_CURLY_BRACKET != fLexerInput->MoveToNextChar())	return false;
	if (!fLexerInput->HasMoreChars())	return false;

	// Now we expect to read the name of the exception
	VString exceptionName;
	while (true) {
		if (!fLexerInput->HasMoreChars())	return false;
		ch = fLexerInput->MoveToNextChar();

		if (IsLineEnding( ch )) { ConsumeLineEnding( ch ); return false; }
		if (CHAR_RIGHT_CURLY_BRACKET == ch) break;
		exceptionName.AppendUniChar( ch );
	}

	// Now that we have the exception name clause, we can skip whitespaces and look
	// for the description
	if (!SkipWhitespaces( toss ))		return false;

	VString description;
	if (!ConsumeComment( description ))	return false;

	fLastElement = new ExceptionElement( exceptionName, description );
	return true;
}
bool ScriptDocLexer::ConsumeReturnTag()
{
	UniChar	ch;
	bool	toss;

	if ( ! SkipWhitespaces( toss ) )
		return false;

	if ( ! fLexerInput->HasMoreChars() )
		return false;

	// We expect the next character to be an open curly bracket.
	if ( CHAR_LEFT_CURLY_BRACKET != fLexerInput->MoveToNextChar() )
		return false;

	if ( ! fLexerInput->HasMoreChars() )
		return false;

	// Now we expect to read the type list
	VString typeList;
	while (true)
	{
		if ( ! fLexerInput->HasMoreChars() )
			return false;

		ch = fLexerInput->MoveToNextChar();

		if ( IsLineEnding( ch ) )
		{
			ConsumeLineEnding( ch );
			return false; 
		}

		if (CHAR_RIGHT_CURLY_BRACKET == ch)
			break;
		typeList.AppendUniChar( ch );
	}

	if ( ! SkipWhitespaces( toss ) )
		return false;

	// Now we can find the description of the return value
	VString description;
	ConsumeComment( description );

	fLastElement = new ReturnElement( typeList, description );
	return true;
}
bool ScriptDocLexer::ConsumeMethodTag()
{
	UniChar ch;

	// So it turns out that sometimes there will be a method name here.  So we will eat anything up to the
	// end of the line and just ignore it.
	fLastElement = new MethodElement();
	if (fLexerInput->HasMoreChars()) {
		ch = fLexerInput->PeekAtNextChar();
		if (CHAR_ASTERISK != ch && !IsLineEnding( ch )) {
			VString toss;
			ConsumeComment( toss );
		}
	}
	return true;
}
bool ScriptDocLexer::ConsumeParamTag()
{
	// Param tags are one of the most complex ScriptDoc tags.  It consists of a list of
	// types followed by a name and a description.  We've already processed the @param
	// part of the element, so we want to find the type list.
	UniChar ch;
	bool toss;
	if (!SkipWhitespaces( toss ))		return false;
	if (!fLexerInput->HasMoreChars())	return false;

	// Unfortunately, there's no real concensus on how this tag is handled.  There's the
	// ScriptDoc Way, but then there's also a very common variation.  Basically, it can
	// either be @param {types} Name Comments or @param Name {types} Comments, and we
	// really want to support both versions.  Normal order is the ScriptDoc way.
	bool bIsNormalOrder = (fLexerInput->PeekAtNextChar() == CHAR_LEFT_CURLY_BRACKET);

	bool bDoFurtherProcessing;
	VString typeList, paramName, description;
	bool isOptional;

	if (bIsNormalOrder)
	{
		ConsumeTypes( typeList, bDoFurtherProcessing );
		if (!SkipWhitespaces( toss ))
			return false;
		if (!ConsumeName( paramName, isOptional, bDoFurtherProcessing ) || paramName.IsEmpty() )
			return false;
	}
	else
	{
		if (!ConsumeName( paramName, isOptional, bDoFurtherProcessing ))
			return false;
		if (bDoFurtherProcessing)
			ConsumeTypes( typeList, bDoFurtherProcessing );
	}

	if (bDoFurtherProcessing)
	{
		if (!SkipWhitespaces( toss ))
			return false;
		// Now we can find the description of the parameter
		ConsumeComment( description );
	}

	fLastElement = new ParamElement( paramName, typeList, description, isOptional );
	return true;
}
bool ScriptDocLexer::ConsumeThrowsTag()
{
	bool toss;

	if (!SkipWhitespaces( toss ))		return false;
	if (!fLexerInput->HasMoreChars())	return false;

	VString type, description;
	bool isOptional, bDoFurtherProcessing;

	// Look for the optional type
	if (ConsumeTypes(type, bDoFurtherProcessing))
		if (!SkipWhitespaces( toss )) return false;

	// Now we can find the optional description
	if (bDoFurtherProcessing)
		ConsumeComment( description );

	fLastElement = new ThrowsElement( type, description );
	return true;	
}
/**
 * This method is called just after a "<" has been consumed 
 * and we know we're at the start of some kind of tagged 
 * element. We don't know yet if it's a tag or a comment.
 * 
 * @param   aChar is the last char read
 * @param   aToken is the out arg holding our new token (the function allocates
 *                 the return token using mTokenAllocator).
 * @param   aScanner represents our input source
 * @param   aFlushTokens is an OUT parameter use to tell consumers to flush
 *                       the current tokens after processing the current one.
 * @return  error code.
 */
nsresult
nsHTMLTokenizer::ConsumeTag(PRUnichar aChar,
                            CToken*& aToken,
                            nsScanner& aScanner,
                            bool& aFlushTokens)
{
  PRUnichar theNextChar, oldChar;
  nsresult result = aScanner.Peek(aChar, 1);

  if (NS_OK == result) {
    switch (aChar) {
      case kForwardSlash:
        result = aScanner.Peek(theNextChar, 2);

        if (NS_OK == result) {
          // Get the original "<" (we've already seen it with a Peek)
          aScanner.GetChar(oldChar);

          // XML allows non ASCII tag names, consume this as an end tag. This
          // is needed to make XML view source work
          bool isXML = !!(mFlags & NS_IPARSER_FLAG_XML);
          if (nsCRT::IsAsciiAlpha(theNextChar) ||
              kGreaterThan == theNextChar      ||
              (isXML && !nsCRT::IsAscii(theNextChar))) {
            result = ConsumeEndTag(aChar, aToken, aScanner);
          } else {
            result = ConsumeComment(aChar, aToken, aScanner);
          }
        }

        break;

      case kExclamation:
        result = aScanner.Peek(theNextChar, 2);

        if (NS_OK == result) {
          // Get the original "<" (we've already seen it with a Peek)
          aScanner.GetChar(oldChar);

          if (kMinus == theNextChar || kGreaterThan == theNextChar) {
            result = ConsumeComment(aChar, aToken, aScanner);
          } else {
            result = ConsumeSpecialMarkup(aChar, aToken, aScanner);
          }
        }
        break;

      case kQuestionMark:
        // It must be a processing instruction...
        // Get the original "<" (we've already seen it with a Peek)
        aScanner.GetChar(oldChar);
        result = ConsumeProcessingInstruction(aChar, aToken, aScanner);
        break;

      default:
        // XML allows non ASCII tag names, consume this as a start tag.
        bool isXML = !!(mFlags & NS_IPARSER_FLAG_XML);
        if (nsCRT::IsAsciiAlpha(aChar) ||
            (isXML && !nsCRT::IsAscii(aChar))) {
          // Get the original "<" (we've already seen it with a Peek)
          aScanner.GetChar(oldChar);
          result = ConsumeStartTag(aChar, aToken, aScanner, aFlushTokens);
        } else {
          // We are not dealing with a tag. So, don't consume the original
          // char and leave the decision to ConsumeText().
          result = ConsumeText(aToken, aScanner);
        }
    }
  }

  // Last ditch attempt to make sure we don't lose data.
  if (kEOF == result && !aScanner.IsIncremental()) {
    // Whoops, we don't want to lose any data! Consume the rest as text.
    // This normally happens for either a trailing < or </
    result = ConsumeText(aToken, aScanner);
  }

  return result;
}
bool ScriptDocLexer::AdvanceOneToken( int &outToken )
{
	// Clear out our last token's text and any tag values we've stored up
	fLastElement = NULL;

	// Start by skipping any whitespaces that we run into
	bool consumedWhitespace = false;
	if (!SkipWhitespaces( consumedWhitespace ))	return false;

	// Now snag the next character from the stream so we can determine how
	// to handle it.
	if (!fLexerInput->HasMoreChars())	return false;
	UniChar ch = fLexerInput->PeekAtNextChar();

	if (IsScriptDocStart( ch )) {
		ConsumeScriptDocStart();
		outToken = ScriptDocTokenValues::START;
		return true;
	}
	
	// Now that we've handled the start and stop cases for the tag, we need to consume
	// some more data from the line.  Every ScriptDoc line starts with at least one asterisk, 
	// but possibly more.  We will eat all of the asterisks we find.
	if (ch != CHAR_ASTERISK)	return false;
	do {
		ch = fLexerInput->MoveToNextChar();
	} while (ch == CHAR_ASTERISK);

	// If the very next character is a solidus, that means we've reached the end of the scriptdoc
	// comment
	if (ch == CHAR_SOLIDUS) {
		outToken = ScriptDocTokenValues::END;
		return true;
	}

	// Put the last token we grabbed during asterisk processing back onto the stream
	fLexerInput->MoveToPreviousChar();

	// Now we can skip any whitespaces that remain
	if (!SkipWhitespaces( consumedWhitespace ))	return false;

	// Having done that, we can continue to look for semantic information.
	ch = fLexerInput->HasMoreChars() ? fLexerInput->PeekAtNextChar() : -1;

	if (-1 == ch) {
		// This is a santity check for the end of input
		return false;
	} else if (IsLineEnding( ch )) {
		ConsumeLineEnding( fLexerInput->MoveToNextChar() );
		// If we hit a line ending, then we just want to start this whole process over again
		return AdvanceOneToken( outToken );
	} else if (IsScriptDocTag( ch )) {
		// We found a ScriptDoc tag, so let's eat it
		fFoundTags = true;
		if (!ConsumeScriptDocTag())	return false;
		outToken = ScriptDocTokenValues::ELEMENT;
		return true;
	} else {
		// The only thing left is the comment section.  Each ScriptDoc can have one and only
		// one comment to it, and it is supposed to be found before any tags.  It can span multiple
		// lines.
		if (fFoundComment || fFoundTags)				return false;
		fFoundComment = true;
		VString text;
		if (!ConsumeComment( text ))							return false;
		fLastElement = new CommentElement( text );
		outToken = ScriptDocTokenValues::ELEMENT;
		return true;
	}

	return true;
}
bool ScriptDocLexer::ConsumeScriptDocTag()
{
	// We need to consume the @ token for the tag.  We know it exists because
	// we've already peeked at it
	if (!testAssert( fLexerInput->MoveToNextChar() == CHAR_COMMERCIAL_AT ))	return false;

	// After the @ symbol comes the name of the tag, followed by some whitespace.  Any
	// whitespace between the @ and the tag name will be eaten
	bool toss = false;
	if (!SkipWhitespaces( toss ))	return false;

	UniChar ch;
	VString text;
	bool bLineEnded = false;
	while (true) {
		if (!fLexerInput->HasMoreChars())	return false;
		ch = fLexerInput->MoveToNextChar();
		if (IsWhitespace( ch )) break;
		if (IsLineEnding( ch )) {
			ConsumeLineEnding( ch );
			bLineEnded = true;
			break;
		}
		text.AppendUniChar( ch );
	}

	// Skip any whitespace between the tag name and the tag contents
	if (!SkipWhitespaces( toss ))	return false;

	// Now that we have the tag name, we can create the appropriate class to represent
	// it.
	VString simpleText;
	if (text == "author" && ConsumeComment( simpleText ))
	{
		fLastElement = new AuthorElement( simpleText );
	}
	else if (text == "alias" && ConsumeComment( simpleText ))
	{
		fLastElement = new AliasElement( simpleText );
	} 
	else if (text == "attributes" && ConsumeComment( simpleText ))
	{
		fLastElement = new AttributesElement( simpleText );
	}
	else if (text == "class" && ConsumeComment( simpleText ))
	{
		fLastElement = new ClassElement( simpleText );
	}
	else if (text == "classDescription" && ConsumeComment( simpleText ))
	{
		fLastElement = new ClassDescriptionElement( simpleText );
	}
	else if (text == "constructor")
	{
		fLastElement = new ConstructorElement();
	}
	else if (text == "default" && ConsumeComment( simpleText ))
	{
		fLastElement = new DefaultElement(simpleText);
	}
	else if (text == "deprecated" && ConsumeComment( simpleText ))
	{
		fLastElement = new DeprecatedElement(simpleText);
	}
	else if (text == "exception")
	{
		return ConsumeExceptionTag();
	}
	else if ( (text == "extends" || text == "augments" || text == "inherits") && ConsumeComment( simpleText ))
	{
		fLastElement = new ExtendsElement(simpleText);
	}
	else if (text == "id" && ConsumeComment( simpleText ))
	{
		fLastElement = new IdElement( simpleText );
	}
	else if (text == "inherits" && ConsumeComment( simpleText ))
	{
		fLastElement = new InheritsElement( simpleText );
	}
	else if (text == "memberOf" && ConsumeComment( simpleText ))
	{
		fLastElement = new MemberOfElement( simpleText );
	}
	else if (text == "method")
	{
		return ConsumeMethodTag();
	}
	else if (text == "module" && ConsumeComment( simpleText ))
	{
		fLastElement = new ModuleElement( simpleText );
	}
	else if (text == "namespace" && ConsumeComment( simpleText ))
	{
		fLastElement = new NamespaceElement( simpleText );
	}
	else if (text == "param")
	{
		return ConsumeParamTag();
	}
	else if (text == "paramValue")
	{
		return ConsumeParamValueTag();
	}
	else if (text == "private")
	{
		fLastElement = new PrivateElement();
	}
	else if (text == "projectDescription" && ConsumeComment( simpleText ))
	{
		fLastElement = new ProjectDescriptionElement( simpleText );
	}
	else if (text == "property")
	{
		return ConsumePropertyTag();
	}
	else if ( (text == "require" ||text == "requires") && ConsumeComment( simpleText ))
	{
		fLastElement = new RequiresElement( simpleText );
	}
	else if (text == "return" || text == "returns" || text == "result")
	{
		return ConsumeReturnTag();
	}
	else if (text == "sdoc" && ConsumeComment( simpleText ))
	{
		fLastElement = new SDocElement( simpleText );
	}
	else if (text == "see")
	{
		return ConsumeSeeTag();
	}
	else if (text == "since" && ConsumeComment( simpleText ))
	{
		fLastElement = new SinceElement( simpleText );
	}
	else if (text == "static")
	{
		fLastElement = new StaticElement();
	}
	else if (text == "throws" || text == "throw")
	{
		return ConsumeThrowsTag();
	}
	else if (text == "type")
	{
		return ConsumeTypeTag();
	}
	else if (text == "version" && ConsumeComment( simpleText ))
	{
		fLastElement = new VersionElement( simpleText );
	}
	else
	{
		// This is an unsupported tag, so make an Unknown tag to handle it.  Unknown tags can
		// have comments following them, or just a newline signifying it's time for another tag.
		// We don't know which it is supposed to be, so we will skip whitespaces and check to see
		// if there's a newline.  If there is, then it's assumed to be a tag with no comments.
		if (bLineEnded || ConsumeComment( simpleText ))
		{
			fLastElement = new UnknownElement( text, simpleText );
		}
		else
		{
			return false;
		}
	}
	return true;
}
Example #10
0
void CFile::SkipWhitespace()
{
    while (ConsumeHorizontalWhitespace() || ConsumeNewline() || ConsumeComment())
        ;
}