Revise enum documentation autogeneration.

This adds a new subclass of EnumType, CommentedEnumType, and removes
any previous changes to EnumType that were done to support the
autodoc framework.

Dummy CommentedEnumType and ID's are constructed in parallel with the
real EnumType ID's during parsing and passed on to the autodoc framework.

This allows the generated documentation to track enum redefs, with
a special case being the "Notice" enum type.
This commit is contained in:
Jon Siwek 2011-03-15 14:51:50 -05:00
parent b1dc5d3a1c
commit f67c0892e5
7 changed files with 107 additions and 56 deletions

View file

@ -40,6 +40,7 @@ BroDoc::BroDoc(const std::string& sourcename)
else
fprintf(stdout, "Created reST document: %s\n", reST_filename.c_str());
#endif
notices = 0;
}
BroDoc::~BroDoc()
@ -50,9 +51,10 @@ BroDoc::~BroDoc()
FreeBroDocObjPtrList(options);
FreeBroDocObjPtrList(state_vars);
FreeBroDocObjPtrList(types);
FreeBroDocObjPtrList(notices);
FreeBroDocObjPtrList(events);
FreeBroDocObjPtrList(functions);
FreeBroDocObjPtrList(redefs);
if ( notices ) delete notices;
}
void BroDoc::SetPacketFilter(const std::string& s)
@ -90,6 +92,10 @@ void BroDoc::WriteDocFile() const
WriteStringList(" :bro:script: `%s`\n",
" :bro:script: `%s`\n\n", imports);
WriteSectionHeading("Notices", '-');
if ( notices )
notices->WriteReST(reST_file);
WriteSectionHeading("Port Analysis", '-');
WriteStringList("%s", port_analysis);
@ -100,15 +106,16 @@ void BroDoc::WriteDocFile() const
WriteBroDocObjList(options, true, "Options", '~');
WriteBroDocObjList(state_vars, true, "State Variables", '~');
WriteBroDocObjList(types, true, "Types", '~');
WriteBroDocObjList(notices, true, "Notices", '~');
WriteBroDocObjList(events, true, "Events", '~');
WriteBroDocObjList(functions, true, "Functions", '~');
WriteBroDocObjList(redefs, true, "Redefinitions", '~');
WriteSectionHeading("Private Interface", '-');
WriteBroDocObjList(state_vars, false, "State Variables", '~');
WriteBroDocObjList(types, false, "Types", '~');
WriteBroDocObjList(events, false, "Events", '~');
WriteBroDocObjList(functions, false, "Functions", '~');
WriteBroDocObjList(redefs, false, "Redefinitions", '~');
}
void BroDoc::WriteStringList(const char* format,

View file

@ -95,9 +95,10 @@ public:
void AddOption(const BroDocObj* o) { options.push_back(o); }
void AddStateVar(const BroDocObj* o) { state_vars.push_back(o); }
void AddType(const BroDocObj* o) { types.push_back(o); }
void AddNotice(const BroDocObj* o) { notices.push_back(o); }
void AddNotice(const BroDocObj* o) { notices = o; }
void AddEvent(const BroDocObj* o) { events.push_back(o); }
void AddFunction(const BroDocObj* o) { functions.push_back(o); }
void AddRedef(const BroDocObj* o) { redefs.push_back(o); }
/**
* Gets the name of the Bro script source file for which reST
@ -128,9 +129,10 @@ protected:
std::list<const BroDocObj*> options; // identifiers with &redef attr
std::list<const BroDocObj*> state_vars; // identifiers without &redef?
std::list<const BroDocObj*> types;
std::list<const BroDocObj*> notices;
const BroDocObj* notices;
std::list<const BroDocObj*> events;
std::list<const BroDocObj*> functions;
std::list<const BroDocObj*> redefs;
/**
* Writes out a list of strings to the reST document.

View file

@ -4,16 +4,19 @@
#include "ID.h"
#include "BroDocObj.h"
BroDocObj::BroDocObj(const ID* id, std::list<std::string>*& reST)
BroDocObj::BroDocObj(const ID* id, std::list<std::string>*& reST,
bool is_fake)
{
broID = id;
reST_doc_strings = reST;
reST = 0;
is_fake_id = is_fake;
}
BroDocObj::~BroDocObj()
{
delete reST_doc_strings;
if ( is_fake_id ) delete broID;
}
void BroDocObj::WriteReST(FILE* file) const

View file

@ -15,8 +15,10 @@ public:
* @param reST a reference to a pointer of a list of strings that
represent the reST documentation for the ID. The pointer
will be set to 0 after this constructor finishes.
* @param is_fake whether the ID* is a dummy just for doc purposes
*/
BroDocObj(const ID* id, std::list<std::string>*& reST);
BroDocObj(const ID* id, std::list<std::string>*& reST,
bool is_fake = false);
/**
* BroDocObj destructor
@ -60,6 +62,7 @@ public:
protected:
std::list<std::string>* reST_doc_strings;
const ID* broID;
bool is_fake_id; /**< Whether the ID* is a dummy just for doc purposes */
private:
};

View file

@ -1235,7 +1235,10 @@ EnumType::~EnumType()
{
for ( NameMap::iterator iter = names.begin(); iter != names.end(); ++iter )
delete [] iter->first;
}
CommentedEnumType::~CommentedEnumType()
{
for ( CommentMap::iterator iter = comments.begin(); iter != comments.end(); ++iter )
{
delete [] iter->first;
@ -1272,7 +1275,7 @@ void EnumType::AddName(const string& module_name, const char* name, bro_int_t va
AddNameInternal(module_name, name, val, is_export);
}
void EnumType::AddComment(const string& module_name, const char* name, const char* comment)
void CommentedEnumType::AddComment(const string& module_name, const char* name, const char* comment)
{
if ( ! comment ) return;
@ -1323,6 +1326,12 @@ void EnumType::AddNameInternal(const string& module_name, const char* name, bro_
names[copy_string(fullname.c_str())] = val;
}
void CommentedEnumType::AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export)
{
string fullname = make_full_var_name(module_name.c_str(), name);
names[copy_string(fullname.c_str())] = val;
}
bro_int_t EnumType::Lookup(const string& module_name, const char* name)
{
NameMap::iterator pos =
@ -1344,7 +1353,7 @@ const char* EnumType::Lookup(bro_int_t value)
return 0;
}
void EnumType::DescribeReST(ODesc* d) const
void CommentedEnumType::DescribeReST(ODesc* d) const
{
// create temporary, reverse name map so that enums can be documented
// in ascending order of their actual integral value instead of by name
@ -1384,10 +1393,6 @@ bool EnumType::DoSerialize(SerialInfo* info) const
SERIALIZE(false)) )
return false;
if ( generate_documentation )
if ( ! (SERIALIZE((unsigned int) comments.size())) )
return false;
for ( NameMap::const_iterator iter = names.begin();
iter != names.end(); ++iter )
{
@ -1395,14 +1400,6 @@ bool EnumType::DoSerialize(SerialInfo* info) const
return false;
}
if ( generate_documentation )
for ( CommentMap::const_iterator it = comments.begin();
it != comments.end(); ++ it )
{
if ( ! SERIALIZE(it->first) || ! SERIALIZE(it->second) )
return false;
}
return true;
}
@ -1411,7 +1408,6 @@ bool EnumType::DoUnserialize(UnserialInfo* info)
DO_UNSERIALIZE(BroType);
unsigned int len;
unsigned int cmnt_len;
bool dummy;
if ( ! UNSERIALIZE(&counter) ||
! UNSERIALIZE(&len) ||
@ -1419,10 +1415,6 @@ bool EnumType::DoUnserialize(UnserialInfo* info)
! UNSERIALIZE(&dummy) )
return false;
if ( generate_documentation )
if ( ! UNSERIALIZE(&cmnt_len) )
return false;
while ( len-- )
{
const char* name;
@ -1433,16 +1425,6 @@ bool EnumType::DoUnserialize(UnserialInfo* info)
names[name] = val;
}
if ( generate_documentation )
while ( cmnt_len-- )
{
const char* cmnt;
const char* name;
if ( ! (UNSERIALIZE_STR(&name, 0) && UNSERIALIZE_STR(&cmnt, 0)) )
return false;
comments[name] = cmnt;
}
return true;
}

View file

@ -480,26 +480,18 @@ public:
// added that aren't likewise explicitly initalized.
void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export);
void AddComment(const string& module_name, const char* name, const char* comment);
// -1 indicates not found.
bro_int_t Lookup(const string& module_name, const char* name);
const char* Lookup(bro_int_t value); // Returns 0 if not found
void DescribeReST(ODesc* d) const;
protected:
DECLARE_SERIAL(EnumType)
void AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export);
virtual void AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export);
typedef std::map< const char*, bro_int_t, ltstr > NameMap;
NameMap names;
// comments are only filled when in "documentation mode"
typedef std::map< const char*, const char*, ltstr > CommentMap;
CommentMap comments;
// The counter is initialized to 0 and incremented on every implicit
// auto-increment name that gets added (thus its > 0 if
// auto-increment is used). Once an explicit value has been
@ -509,6 +501,24 @@ protected:
bro_int_t counter;
};
class CommentedEnumType: public EnumType {
public:
CommentedEnumType() {}
~CommentedEnumType();
void DescribeReST(ODesc* d) const;
void AddComment(const string& module_name, const char* name, const char* comment);
protected:
// This overriden method does not install the given ID name into a
// scope and it also does not do any kind of checking that the provided
// name already exists.
void AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export);
// comments are only filled when in "documentation mode"
typedef std::map< const char*, const char*, ltstr > CommentMap;
CommentMap comments;
};
class VectorType : public BroType {
public:
VectorType(BroType* t);

View file

@ -116,6 +116,7 @@ bool resolving_global_ID = false;
ID* func_id = 0;
EnumType *cur_enum_type = 0;
CommentedEnumType *cur_enum_type_doc = 0;
const char* cur_enum_elem_id = 0;
static void parser_new_enum (void)
@ -123,6 +124,10 @@ static void parser_new_enum (void)
/* Starting a new enum definition. */
assert(cur_enum_type == NULL);
cur_enum_type = new EnumType();
// for documentation purpose, a separate type object is created
// in order to avoid overlap that can be caused by redefs
if ( generate_documentation )
cur_enum_type_doc = new CommentedEnumType();
}
static void parser_redef_enum (ID *id)
@ -138,6 +143,24 @@ static void parser_redef_enum (ID *id)
if ( ! cur_enum_type )
id->Error("not an enum");
}
if ( generate_documentation )
cur_enum_type_doc = new CommentedEnumType();
}
static void add_enum_comment (const char* comment)
{
cur_enum_type_doc->AddComment(current_module, cur_enum_elem_id, comment);
}
static ID* create_dummy_id (const char* name, const BroType* type)
{
// normally, install_ID() figures out the right IDScope
// but it doesn't matter for the dummy ID so use SCOPE_GLOBAL
ID* fake_id = new ID(copy_string(name), SCOPE_GLOBAL, is_export);
fake_id->SetType(cur_enum_type_doc);
fake_id->MakeType();
return fake_id;
}
static char* concat_opt_docs (const char* pre, const char* post)
@ -615,7 +638,7 @@ enum_body:
$$ = cur_enum_type;
if ( generate_documentation )
{
cur_enum_type->AddComment(current_module, cur_enum_elem_id, $2);
add_enum_comment($2);
cur_enum_elem_id = 0;
}
cur_enum_type = NULL;
@ -625,7 +648,7 @@ enum_body:
$$ = cur_enum_type;
if ( generate_documentation )
{
cur_enum_type->AddComment(current_module, cur_enum_elem_id, $3);
add_enum_comment($3);
cur_enum_elem_id = 0;
}
cur_enum_type = NULL;
@ -636,12 +659,12 @@ enum_body_list:
enum_body_elem opt_post_doc_list
{
if ( generate_documentation )
cur_enum_type->AddComment(current_module, cur_enum_elem_id, $2);
add_enum_comment($2);
}
| enum_body_list ',' opt_post_doc_list
{
if ( generate_documentation )
cur_enum_type->AddComment(current_module, cur_enum_elem_id, $3);
add_enum_comment($3);
} enum_body_elem
;
@ -662,8 +685,9 @@ enum_body_elem:
if ( generate_documentation )
{
cur_enum_type_doc->AddName(current_module, $2, $4->InternalUnsigned(), is_export);
cur_enum_elem_id = $2;
cur_enum_type->AddComment(current_module, cur_enum_elem_id, $1);
add_enum_comment($1);
}
}
@ -684,8 +708,9 @@ enum_body_elem:
if ( generate_documentation )
{
cur_enum_type_doc->AddName(current_module, $2, is_export);
cur_enum_elem_id = $2;
cur_enum_type->AddComment(current_module, cur_enum_elem_id, $1);
add_enum_comment($1);
}
}
;
@ -957,24 +982,43 @@ decl:
add_global($2, $3, $4, $5, $6, VAR_REDEF);
if ( generate_documentation )
{
// TODO: eventually handle type redefs that add record fields
// TODO: handle more types of redefs, e.g. adding record fields
}
}
| TOK_REDEF TOK_ENUM global_id TOK_ADD_TO
'{' { parser_redef_enum($3); } enum_body '}' ';'
'{' { parser_redef_enum($3); do_doc_token_start(); } enum_body '}' ';'
{
/* no action */
// TODO: handle "Notice" redefinitions for doc framework
do_doc_token_stop();
if ( generate_documentation )
{
ID* fake_id = create_dummy_id($3->Name(), cur_enum_type_doc);
cur_enum_type_doc = 0;
BroDocObj* o = new BroDocObj(fake_id, reST_doc_comments, true);
if ( streq(fake_id->Name(), "Notice" ) )
current_reST_doc->AddNotice(o);
else
current_reST_doc->AddRedef(o);
}
}
| TOK_TYPE global_id ':' refined_type opt_attr ';'
{
add_type($2, $4, $5, 0);
if ( generate_documentation )
{
if ( $2->AsType()->Tag() == TYPE_ENUM && cur_enum_type_doc )
{
ID* fake = create_dummy_id($2->Name(), cur_enum_type_doc);
cur_enum_type_doc = 0;
current_reST_doc->AddType(
new BroDocObj(fake, reST_doc_comments, true));
}
else
current_reST_doc->AddType(
new BroDocObj($2, reST_doc_comments));
}
}
| TOK_EVENT event_id ':' refined_type opt_attr ';'
{