12d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko//===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===// 22d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko// 32d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko// The LLVM Compiler Infrastructure 42d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko// 52d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko// This file is distributed under the University of Illinois Open Source 62d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko// License. See LICENSE.TXT for details. 72d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko// 82d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko//===----------------------------------------------------------------------===// 92d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 102d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko#include "clang/AST/CommentBriefParser.h" 11aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko#include "clang/AST/CommentCommandTraits.h" 1255e1808c6064ace116e458ab82abf33d3f83659aDmitri Gribenko#include "llvm/ADT/StringSwitch.h" 132d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 142d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenkonamespace clang { 152d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenkonamespace comments { 162d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 17d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenkonamespace { 180ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenkoinline bool isWhitespace(char C) { 190ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko return C == ' ' || C == '\n' || C == '\r' || 200ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko C == '\t' || C == '\f' || C == '\v'; 210ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko} 220ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko 23d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko/// Convert all whitespace into spaces, remove leading and trailing spaces, 24d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko/// compress multiple spaces into one. 25d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenkovoid cleanupBrief(std::string &S) { 26d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko bool PrevWasSpace = true; 27d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko std::string::iterator O = S.begin(); 28d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko for (std::string::iterator I = S.begin(), E = S.end(); 29d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko I != E; ++I) { 30d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko const char C = *I; 310ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko if (isWhitespace(C)) { 32d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko if (!PrevWasSpace) { 33d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko *O++ = ' '; 34d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko PrevWasSpace = true; 35d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko } 36d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko continue; 37d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko } else { 38d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko *O++ = C; 39d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko PrevWasSpace = false; 40d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko } 41d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko } 42d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko if (O != S.begin() && *(O - 1) == ' ') 43d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko --O; 44d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko 45d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko S.resize(O - S.begin()); 46d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko} 470ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko 480ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenkobool isWhitespace(StringRef Text) { 490ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko for (StringRef::const_iterator I = Text.begin(), E = Text.end(); 500ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko I != E; ++I) { 510ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko if (!isWhitespace(*I)) 520ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko return false; 530ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko } 540ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko return true; 550ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko} 56aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko} // unnamed namespace 5755e1808c6064ace116e458ab82abf33d3f83659aDmitri Gribenko 58aa58081902ad31927df02e8537d972eabe29d6dfDmitri GribenkoBriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) : 59aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko L(L), Traits(Traits) { 60aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko // Get lookahead token. 61aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko ConsumeToken(); 6255e1808c6064ace116e458ab82abf33d3f83659aDmitri Gribenko} 63d558b5238df74ef3cb76d7125375a5c28fe0eaa9Dmitri Gribenko 642d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenkostd::string BriefParser::Parse() { 6572021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko std::string FirstParagraphOrBrief; 6672021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko std::string ReturnsParagraph; 672d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko bool InFirstParagraph = true; 682d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko bool InBrief = false; 6972021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko bool InReturns = false; 702d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 712d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko while (Tok.isNot(tok::eof)) { 722d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko if (Tok.is(tok::text)) { 73c0b8324d6f68dfc2221257cdb83e39b974431c0bDmitri Gribenko if (InFirstParagraph || InBrief) 7472021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko FirstParagraphOrBrief += Tok.getText(); 7572021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko else if (InReturns) 7672021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko ReturnsParagraph += Tok.getText(); 772d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko ConsumeToken(); 782d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko continue; 792d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko } 802d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 818536fa14ee1048e5e2d62cb3dc11fc640c7dc00dFariborz Jahanian if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) { 82e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); 83e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko if (Info->IsBriefCommand) { 8472021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko FirstParagraphOrBrief.clear(); 85f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko InBrief = true; 86f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko ConsumeToken(); 87f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko continue; 88f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko } 89e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko if (Info->IsReturnsCommand) { 9072021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko InReturns = true; 910ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko InBrief = false; 920ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko InFirstParagraph = false; 9372021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko ReturnsParagraph += "Returns "; 940ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko ConsumeToken(); 950ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko continue; 9672021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko } 9755e1808c6064ace116e458ab82abf33d3f83659aDmitri Gribenko // Block commands implicitly start a new paragraph. 98e4330a302ac20b41b9800267ebd4b5b01f8553f8Dmitri Gribenko if (Info->IsBlockCommand) { 99f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko // We found an implicit paragraph end. 100f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko InFirstParagraph = false; 10157aceb227d192ce41f5412a53d451354e90dd792Dmitri Gribenko if (InBrief) 102f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko break; 103f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko } 1042d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko } 1052d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 1062d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko if (Tok.is(tok::newline)) { 107c0b8324d6f68dfc2221257cdb83e39b974431c0bDmitri Gribenko if (InFirstParagraph || InBrief) 10872021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko FirstParagraphOrBrief += ' '; 10972021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko else if (InReturns) 11072021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko ReturnsParagraph += ' '; 1112d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko ConsumeToken(); 1122d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 1130ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // If the next token is a whitespace only text, ignore it. Thus we allow 1140ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // two paragraphs to be separated by line that has only whitespace in it. 1150ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // 1160ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // We don't need to add a space to the parsed text because we just added 1170ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // a space for the newline. 1180ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko if (Tok.is(tok::text)) { 1190ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko if (isWhitespace(Tok.getText())) 1200ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko ConsumeToken(); 1210ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko } 1220ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko 1232d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko if (Tok.is(tok::newline)) { 1242d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko ConsumeToken(); 1250ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // We found a paragraph end. This ends the brief description if 1260ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // \\brief command or its equivalent was explicitly used. 1270ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // Stop scanning text because an explicit \\brief paragraph is the 1280ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // preffered one. 12957aceb227d192ce41f5412a53d451354e90dd792Dmitri Gribenko if (InBrief) 130f199b9cd4af562029a3c7b82c4672819b2c39e70Dmitri Gribenko break; 1310ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // End first paragraph if we found some non-whitespace text. 1320ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief)) 1330ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko InFirstParagraph = false; 1340ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko // End the \\returns paragraph because we found the paragraph end. 1350ac4ec7f1c79a13f813fa644997a4b89ac0ba3aaDmitri Gribenko InReturns = false; 1362d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko } 1372d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko continue; 1382d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko } 1392d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 1402d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko // We didn't handle this token, so just drop it. 1412d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko ConsumeToken(); 1422d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko } 1432d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 14472021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko cleanupBrief(FirstParagraphOrBrief); 14572021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko if (!FirstParagraphOrBrief.empty()) 14672021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko return FirstParagraphOrBrief; 14772021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko 14872021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko cleanupBrief(ReturnsParagraph); 14972021ff4038cbc48b09a3acb743e319809f086dbDmitri Gribenko return ReturnsParagraph; 1502d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko} 1512d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 1522d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko} // end namespace comments 1532d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko} // end namespace clang 1542d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 1552d44d77fed3200e2eff289f55493317e90d3398cDmitri Gribenko 156