mirror of
https://github.com/zeek/zeek.git
synced 2025-10-07 00:58:19 +00:00
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:
parent
b1dc5d3a1c
commit
f67c0892e5
7 changed files with 107 additions and 56 deletions
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
};
|
||||
|
|
40
src/Type.cc
40
src/Type.cc
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
28
src/Type.h
28
src/Type.h
|
@ -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);
|
||||
|
|
68
src/parse.y
68
src/parse.y
|
@ -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,23 +982,42 @@ 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 )
|
||||
current_reST_doc->AddType(
|
||||
new BroDocObj($2, reST_doc_comments));
|
||||
{
|
||||
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 ';'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue