ScriptDocComment *ScriptDocComment::Create( const VString &text ) { ScriptDocLexer *lexer = new ScriptDocLexer( const_cast< VString * >( &text ) ); // If the first token we lex isn't a start token, then we've got a problem if (ScriptDocTokenValues::START != lexer->GetNextTokenForParser()) { delete lexer; return NULL; } ScriptDocComment *ret = new ScriptDocComment( text ); while (true) { int tk = lexer->GetNextTokenForParser(); // If we reach the end of input before finding an END token, this isn't a valid // ScriptDoc comment if (-1 == tk) { delete lexer; delete ret; return NULL; } // If we find the ending token, then we're done parsing if (ScriptDocTokenValues::END == tk) break; if (ScriptDocTokenValues::ELEMENT == tk) { ret->fElements.push_back( lexer->GetElement() ); } else { delete lexer; delete ret; return NULL; } } // If there are more tokens past the end, then something has gone wrong if (-1 != lexer->GetNextTokenForParser()) { delete lexer; delete ret; return NULL; } delete lexer; return ret; }
void ScriptDocLexer::Test() { ScriptDocLexer *lexer = new ScriptDocLexer(); Element *element = NULL; VString sourceString = "/**\n" "* This is a test script doc comment\n" "*/"; lexer->SetLexerInput( &sourceString ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::START ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element ); xbox_assert( element->Type() == IScriptDocCommentField::kComment ); xbox_assert( static_cast< CommentElement * >( element )->fCommentText == "This is a test script doc comment" ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::END ); sourceString = "/**\n" "*/"; lexer->SetLexerInput( &sourceString ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::START ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::END ); sourceString = "/**\n" "* This is a multiline comment\n" "* that should still work.\n" "*/"; lexer->SetLexerInput( &sourceString ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::START ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element ); xbox_assert( element->Type() == IScriptDocCommentField::kComment ); xbox_assert( static_cast< CommentElement * >( element )->fCommentText == "This is a multiline comment\nthat should still work." ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::END ); sourceString = "/**\n" "* This is a multiline comment\n" "* that should still work.\n" "*\n" "* @author Aaron Ballman [email protected]\n" "*/"; lexer->SetLexerInput( &sourceString ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::START ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element ); xbox_assert( element->Type() == IScriptDocCommentField::kComment ); xbox_assert( static_cast< CommentElement * >( element )->fCommentText == "This is a multiline comment\nthat should still work.\n" ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kAuthor ); xbox_assert( static_cast< AuthorElement * >( element )->fAuthorName == "Aaron Ballman [email protected]" ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::END ); sourceString = "/**\n" "* This is a test for exception tags.\n" "*\n" "* @exception {MemoryException} Throws a memory exception if we've run out of memory.\n" "* @constructor\n" "*/"; lexer->SetLexerInput( &sourceString ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::START ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element ); xbox_assert( element->Type() == IScriptDocCommentField::kComment ); xbox_assert( static_cast< CommentElement * >( element )->fCommentText == "This is a test for exception tags.\n" ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kException ); xbox_assert( static_cast< ExceptionElement * >( element )->fName == "MemoryException" ); xbox_assert( static_cast< ExceptionElement * >( element )->fDesc == "Throws a memory exception if we've run out of memory." ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kConstructor ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::END ); // We want to test multiple parameter elements sourceString = "/**\n" "* @param {String} Name A simple string parameter.\n" "* @param {Integer, Object} Type This can be a number or an object.\n" "* @param {Date} [When] An optional date parameter.\n" "*/"; lexer->SetLexerInput( &sourceString ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::START ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kParam ); xbox_assert( static_cast< ParamElement * >( element )->fName == "Name" ); xbox_assert( static_cast< ParamElement * >( element )->fTypes == "String" ); xbox_assert( static_cast< ParamElement * >( element )->fDesc == "A simple string parameter." ); xbox_assert( static_cast< ParamElement * >( element )->fOptional == false ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kParam ); xbox_assert( static_cast< ParamElement * >( element )->fName == "Type" ); xbox_assert( static_cast< ParamElement * >( element )->fTypes == "Integer, Object" ); xbox_assert( static_cast< ParamElement * >( element )->fDesc == "This can be a number or an object." ); xbox_assert( static_cast< ParamElement * >( element )->fOptional == false ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kParam ); xbox_assert( static_cast< ParamElement * >( element )->fName == "When" ); xbox_assert( static_cast< ParamElement * >( element )->fTypes == "Date" ); xbox_assert( static_cast< ParamElement * >( element )->fDesc == "An optional date parameter." ); xbox_assert( static_cast< ParamElement * >( element )->fOptional == true ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::END ); // We are going to do the same test as above, only with the non-ScriptDoc version of the // param tags, where the type comes after the name sourceString = "/**\n" "* @param Name {String} A simple string parameter.\n" "* @param Type {Integer, Object} This can be a number or an object.\n" "* @param [When] {Date} An optional date parameter.\n" "*/"; lexer->SetLexerInput( &sourceString ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::START ); xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kParam ); xbox_assert( static_cast< ParamElement * >( element )->fName == "Name" ); xbox_assert( static_cast< ParamElement * >( element )->fTypes == "String" ); xbox_assert( static_cast< ParamElement * >( element )->fDesc == "A simple string parameter." ); xbox_assert( static_cast< ParamElement * >( element )->fOptional == false ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kParam ); xbox_assert( static_cast< ParamElement * >( element )->fName == "Type" ); xbox_assert( static_cast< ParamElement * >( element )->fTypes == "Integer, Object" ); xbox_assert( static_cast< ParamElement * >( element )->fDesc == "This can be a number or an object." ); xbox_assert( static_cast< ParamElement * >( element )->fOptional == false ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::ELEMENT ); element = lexer->GetElement(); xbox_assert( element->Type() == IScriptDocCommentField::kParam ); xbox_assert( static_cast< ParamElement * >( element )->fName == "When" ); xbox_assert( static_cast< ParamElement * >( element )->fTypes == "Date" ); xbox_assert( static_cast< ParamElement * >( element )->fDesc == "An optional date parameter." ); xbox_assert( static_cast< ParamElement * >( element )->fOptional == true ); delete element; xbox_assert( lexer->GetNextTokenForParser() == ScriptDocTokenValues::END ); sourceString = "/**\n" "* Testing to ensure that packaged ScriptDocComments work\n" "* just as well as the lexed ones do.\n" "*\n" "* @method\n" "* @see someClass#someOtherMethod\n" "* @memberOf AwesomeClass\n" "* @deprecated\n" "* @author Aaron Ballman\n" "* @version 1.5\n" "*/"; ScriptDocComment *comment = ScriptDocComment::Create( sourceString ); xbox_assert( comment->ElementCount() == 7 ); xbox_assert( comment->GetElement( 0 )->Type() == IScriptDocCommentField::kComment ); xbox_assert( comment->GetElement( 1 )->Type() == IScriptDocCommentField::kMethod ); xbox_assert( comment->GetElement( 2 )->Type() == IScriptDocCommentField::kSee ); xbox_assert( static_cast< SeeElement * >( comment->GetElement( 2 ) )->fClassName == "someClass" ); xbox_assert( static_cast< SeeElement * >( comment->GetElement( 2 ) )->fMethodName == "someOtherMethod" ); xbox_assert( comment->GetElement( 3 )->Type() == IScriptDocCommentField::kMemberOf ); xbox_assert( static_cast< MemberOfElement * >( comment->GetElement( 3 ) )->fClass == "AwesomeClass" ); xbox_assert( comment->GetElement( 4 )->Type() == IScriptDocCommentField::kDeprecated ); xbox_assert( comment->GetElement( 5 )->Type() == IScriptDocCommentField::kAuthor ); xbox_assert( static_cast< AuthorElement * >( comment->GetElement( 5 ) )->fAuthorName == "Aaron Ballman" ); xbox_assert( comment->GetElement( 6 )->Type() == IScriptDocCommentField::kVersion ); xbox_assert( static_cast< VersionElement * >( comment->GetElement( 6 ) )->fVersion == "1.5" ); delete comment; // We are going to do a few more tests, but use the public interface for ScriptDoc parsing std::vector< IScriptDocCommentField * > fields; xbox_assert( gLanguageSyntax->ParseScriptDocComment( sourceString, fields ) ); xbox_assert( fields.size() == 7 ); xbox_assert( fields[ 0 ]->GetKind() == IScriptDocCommentField::kComment ); xbox_assert( fields[ 1 ]->GetKind() == IScriptDocCommentField::kMethod ); xbox_assert( fields[ 2 ]->GetKind() == IScriptDocCommentField::kSee ); xbox_assert( fields[ 3 ]->GetKind() == IScriptDocCommentField::kMemberOf ); xbox_assert( fields[ 4 ]->GetKind() == IScriptDocCommentField::kDeprecated ); xbox_assert( fields[ 5 ]->GetKind() == IScriptDocCommentField::kAuthor ); xbox_assert( fields[ 6 ]->GetKind() == IScriptDocCommentField::kVersion ); for (std::vector< IScriptDocCommentField * >::iterator iter = fields.begin(); iter != fields.end(); ++iter) { (*iter)->Release(); } fields.clear(); sourceString = "/**\n" "* @param {String} Name A simple string parameter.\n" "* @param {Integer, Object} Type This can be a number or an object.\n" "* @param {Date} [When] An optional date parameter.\n" "*/"; xbox_assert( gLanguageSyntax->ParseScriptDocComment( sourceString, fields ) ); xbox_assert( fields.size() == 3 ); VValueBag *values = fields[ 0 ]->GetContents(); xbox_assert( values ); VString valueText; xbox_assert( values->GetString( ScriptDocKeys::Name, valueText ) ); xbox_assert( valueText == "Name" ); xbox_assert( values->GetString( ScriptDocKeys::Types, valueText ) ); xbox_assert( valueText == "String" ); xbox_assert( values->GetString( ScriptDocKeys::Comment, valueText ) ); xbox_assert( valueText == "A simple string parameter." ); values->Release(); values = fields[ 2 ]->GetContents(); xbox_assert( values ); xbox_assert( values->GetString( ScriptDocKeys::Name, valueText ) ); xbox_assert( valueText == "When" ); xbox_assert( values->GetString( ScriptDocKeys::Types, valueText ) ); xbox_assert( valueText == "Date" ); xbox_assert( values->GetString( ScriptDocKeys::Comment, valueText ) ); xbox_assert( valueText == "An optional date parameter." ); bool valueBool = false; xbox_assert( values->GetBool( ScriptDocKeys::IsOptional, valueBool ) ); xbox_assert( valueBool ); values->Release(); for (std::vector< IScriptDocCommentField * >::iterator iter = fields.begin(); iter != fields.end(); ++iter) { (*iter)->Release(); } fields.clear(); sourceString = "/**\n" "* @unknown\n" "* @anotherUnkownTag This is an unknown tag, but we should still display it fine\n" "*/"; comment = ScriptDocComment::Create( sourceString ); xbox_assert( comment ); xbox_assert( comment->ElementCount() == 2 ); xbox_assert( comment->GetElement( 0 )->Type() == IScriptDocCommentField::kUnknown ); xbox_assert( comment->GetElement( 1 )->Type() == IScriptDocCommentField::kUnknown ); xbox_assert( static_cast< UnknownElement * >( comment->GetElement( 0 ) )->fTag == "unknown" ); xbox_assert( static_cast< UnknownElement * >( comment->GetElement( 1 ) )->fTag == "anotherUnkownTag" ); xbox_assert( static_cast< UnknownElement * >( comment->GetElement( 1 ) )->fData == "This is an unknown tag, but we should still display it fine" ); delete comment; sourceString = "/**\n" "* add two number\n" "* @param {Number} n1\n" "* @param {Number} n2\n" "* @type Number\n" "*/"; comment = ScriptDocComment::Create( sourceString ); xbox_assert( comment ); xbox_assert( comment->ElementCount() == 4 ); xbox_assert( comment->GetElement( 0 )->Type() == IScriptDocCommentField::kComment ); xbox_assert( comment->GetElement( 1 )->Type() == IScriptDocCommentField::kParam ); xbox_assert( comment->GetElement( 2 )->Type() == IScriptDocCommentField::kParam ); xbox_assert( comment->GetElement( 3 )->Type() == IScriptDocCommentField::kType ); xbox_assert( static_cast< CommentElement * >( comment->GetElement( 0 ) )->fCommentText == "add two number" ); xbox_assert( comment->GetElement( 1 )->FormatTextForDisplay() == "Parameter Name: n1, Type: Number" ); xbox_assert( comment->GetElement( 2 )->FormatTextForDisplay() == "Parameter Name: n2, Type: Number" ); xbox_assert( static_cast< TypeElement * >( comment->GetElement( 3 ) )->fTypes == "Number" ); delete comment; sourceString = "/**" " * <p>Return a String containing this Number value represented in decimal\n" " * fixed-point notation with <var>fractionDigits</var> digits after the decimal\n" " * point. If <var>fractionDigits</var> is undefined, 0 is assumed.</p>\n" " *\n" " * @ecma 3, 5\n" " *\n" " * @method toFixed\n" " * @throws {RangeError} If <var>fractionDigits</var> greater than 20 or lesser\n" " * than 0\n" " * @param {Number} [fractionDigits] Default to 0\n" " * @return {String}\n" " */"; comment = ScriptDocComment::Create( sourceString ); xbox_assert( comment ); xbox_assert( comment->ElementCount() == 6 ); xbox_assert( comment->GetElement( 0 )->Type() == IScriptDocCommentField::kComment ); xbox_assert( comment->GetElement( 1 )->Type() == IScriptDocCommentField::kUnknown ); xbox_assert( comment->GetElement( 2 )->Type() == IScriptDocCommentField::kMethod ); xbox_assert( comment->GetElement( 3 )->Type() == IScriptDocCommentField::kUnknown ); xbox_assert( static_cast< UnknownElement * >( comment->GetElement( 3 ) )->FormatTextForDisplay() == "throws: {RangeError} If <var>fractionDigits</var> greater than 20 or lesser\nthan 0" ); xbox_assert( comment->GetElement( 4 )->Type() == IScriptDocCommentField::kParam ); xbox_assert( comment->GetElement( 5 )->Type() == IScriptDocCommentField::kReturn ); delete comment; }