mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'origin/topic/jsiwek/type-alias-introspection'
* origin/topic/jsiwek/type-alias-introspection: Add enum_names() BIF to return names of an enum type's values Add type_aliases() BIF for introspecting type-names of types/values Change Type::type_aliases map to store IntrusivePtr Fix lookup_ID() BIF to return enum values
This commit is contained in:
commit
aab99b743d
12 changed files with 301 additions and 13 deletions
3
NEWS
3
NEWS
|
@ -148,6 +148,9 @@ Deprecated Functionality
|
||||||
- Marked the Continuation.h and PacketDumper.h files as deprecated. The code
|
- Marked the Continuation.h and PacketDumper.h files as deprecated. The code
|
||||||
contained within them is unused by Zeek.
|
contained within them is unused by Zeek.
|
||||||
|
|
||||||
|
- ``Type::GetAliases()`` and ``Type::AddAlias()`` are deprecated, use
|
||||||
|
``Type::Aliases()`` and ``Type::RegisterAlias()``.
|
||||||
|
|
||||||
Zeek 3.2.0
|
Zeek 3.2.0
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|
10
src/Type.cc
10
src/Type.cc
|
@ -1348,13 +1348,11 @@ void EnumType::CheckAndAddName(const string& module_name, const char* name,
|
||||||
if ( vals.find(val) == vals.end() )
|
if ( vals.find(val) == vals.end() )
|
||||||
vals[val] = make_intrusive<EnumVal>(IntrusivePtr{NewRef{}, this}, val);
|
vals[val] = make_intrusive<EnumVal>(IntrusivePtr{NewRef{}, this}, val);
|
||||||
|
|
||||||
set<Type*> types = Type::GetAliases(GetName());
|
const auto& types = Type::Aliases(GetName());
|
||||||
set<Type*>::const_iterator it;
|
|
||||||
|
|
||||||
for ( it = types.begin(); it != types.end(); ++it )
|
for ( const auto& t : types )
|
||||||
if ( *it != this )
|
if ( t.get() != this )
|
||||||
(*it)->AsEnumType()->AddNameInternal(module_name, name, val,
|
t->AsEnumType()->AddNameInternal(module_name, name, val, is_export);
|
||||||
is_export);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnumType::AddNameInternal(const string& module_name, const char* name,
|
void EnumType::AddNameInternal(const string& module_name, const char* name,
|
||||||
|
|
57
src/Type.h
57
src/Type.h
|
@ -270,13 +270,64 @@ public:
|
||||||
void SetName(const std::string& arg_name) { name = arg_name; }
|
void SetName(const std::string& arg_name) { name = arg_name; }
|
||||||
const std::string& GetName() const { return name; }
|
const std::string& GetName() const { return name; }
|
||||||
|
|
||||||
typedef std::map<std::string, std::set<Type*> > TypeAliasMap;
|
struct TypePtrComparer {
|
||||||
|
bool operator()(const TypePtr& a, const TypePtr& b) const
|
||||||
|
{ return a.get() < b.get(); }
|
||||||
|
};
|
||||||
|
using TypePtrSet = std::set<TypePtr, TypePtrComparer>;
|
||||||
|
using TypeAliasMap = std::map<std::string, TypePtrSet, std::less<>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a mapping of type-name to all other type names declared as
|
||||||
|
* an alias to it.
|
||||||
|
*/
|
||||||
|
static const TypeAliasMap& GetAliasMap()
|
||||||
|
{ return type_aliases; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given type name has any declared aliases
|
||||||
|
*/
|
||||||
|
static bool HasAliases(std::string_view type_name)
|
||||||
|
{ return Type::type_aliases.find(type_name) != Type::type_aliases.end(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of all type names declared as an aliases to the given
|
||||||
|
* type name. A static empty set is returned if there are no aliases.
|
||||||
|
*/
|
||||||
|
static const TypePtrSet& Aliases(std::string_view type_name)
|
||||||
|
{
|
||||||
|
static TypePtrSet empty;
|
||||||
|
auto it = Type::type_aliases.find(type_name);
|
||||||
|
return it == Type::type_aliases.end() ? empty : it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[deprecated("Remove in v4.1. Use zeek::Type::Aliases() instead.")]]
|
||||||
static std::set<Type*> GetAliases(const std::string& type_name)
|
static std::set<Type*> GetAliases(const std::string& type_name)
|
||||||
{ return Type::type_aliases[type_name]; }
|
{
|
||||||
|
std::set<Type*> rval;
|
||||||
|
for ( const auto& t : Type::type_aliases[type_name] )
|
||||||
|
rval.emplace(t.get());
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a new type alias.
|
||||||
|
* @param type_name the name of the type to register a new alias for.
|
||||||
|
* @param type the associated alias type of *type_name*.
|
||||||
|
* @return true if the alias is now registered or false if the alias was
|
||||||
|
* already previously registered.
|
||||||
|
*/
|
||||||
|
static bool RegisterAlias(std::string_view type_name, TypePtr type)
|
||||||
|
{
|
||||||
|
auto it = Type::type_aliases.find(type_name);
|
||||||
|
if ( it == Type::type_aliases.end() )
|
||||||
|
it = Type::type_aliases.emplace(std::string{type_name}, TypePtrSet{}).first;
|
||||||
|
return it->second.emplace(std::move(type)).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[deprecated("Remove in v4.1. Use zeek::Type::RegisterAlias().")]]
|
||||||
static void AddAlias(const std::string &type_name, Type* type)
|
static void AddAlias(const std::string &type_name, Type* type)
|
||||||
{ Type::type_aliases[type_name].insert(type); }
|
{ Type::type_aliases[type_name].insert({NewRef{}, type}); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Type() = default;
|
Type() = default;
|
||||||
|
|
|
@ -382,10 +382,10 @@ void add_type(ID* id, TypePtr t, std::unique_ptr<std::vector<AttrPtr>> attr)
|
||||||
// Clone the type to preserve type name aliasing.
|
// Clone the type to preserve type name aliasing.
|
||||||
tnew = t->ShallowClone();
|
tnew = t->ShallowClone();
|
||||||
|
|
||||||
Type::AddAlias(new_type_name, tnew.get());
|
Type::RegisterAlias(new_type_name, tnew);
|
||||||
|
|
||||||
if ( new_type_name != old_type_name && ! old_type_name.empty() )
|
if ( new_type_name != old_type_name && ! old_type_name.empty() )
|
||||||
Type::AddAlias(old_type_name, tnew.get());
|
Type::RegisterAlias(old_type_name, tnew);
|
||||||
|
|
||||||
tnew->SetName(id->Name());
|
tnew->SetName(id->Name());
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,7 @@ static void parser_redef_enum (zeek::detail::ID *id)
|
||||||
static void extend_record(zeek::detail::ID* id, std::unique_ptr<zeek::type_decl_list> fields,
|
static void extend_record(zeek::detail::ID* id, std::unique_ptr<zeek::type_decl_list> fields,
|
||||||
std::unique_ptr<std::vector<zeek::detail::AttrPtr>> attrs)
|
std::unique_ptr<std::vector<zeek::detail::AttrPtr>> attrs)
|
||||||
{
|
{
|
||||||
std::set<zeek::Type*> types = zeek::Type::GetAliases(id->Name());
|
const auto& types = zeek::Type::Aliases(id->Name());
|
||||||
|
|
||||||
if ( types.empty() )
|
if ( types.empty() )
|
||||||
{
|
{
|
||||||
|
@ -189,7 +189,7 @@ static void extend_record(zeek::detail::ID* id, std::unique_ptr<zeek::type_decl_
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( auto t : types )
|
for ( const auto& t : types )
|
||||||
{
|
{
|
||||||
auto error = t->AsRecordType()->AddFields(*fields, add_log_attr);
|
auto error = t->AsRecordType()->AddFields(*fields, add_log_attr);
|
||||||
|
|
||||||
|
|
126
src/zeek.bif
126
src/zeek.bif
|
@ -1853,6 +1853,125 @@ function type_name%(t: any%): string
|
||||||
return zeek::make_intrusive<zeek::StringVal>(s);
|
return zeek::make_intrusive<zeek::StringVal>(s);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%%{
|
||||||
|
static std::map<std::string, std::set<std::string>> build_complete_alias_map()
|
||||||
|
{
|
||||||
|
std::map<std::string, std::set<std::string>> rval;
|
||||||
|
|
||||||
|
for ( const auto& [name, alias_types] : zeek::Type::GetAliasMap() )
|
||||||
|
{
|
||||||
|
rval[name].emplace(name);
|
||||||
|
|
||||||
|
for ( const auto& alias_type : alias_types )
|
||||||
|
{
|
||||||
|
const auto& alias_name = alias_type->GetName();
|
||||||
|
rval[name].emplace(alias_name);
|
||||||
|
rval[alias_name].emplace(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const auto& [name, aliases] : rval )
|
||||||
|
{
|
||||||
|
std::map<std::string, bool> more;
|
||||||
|
|
||||||
|
for ( const auto& alias_name : aliases )
|
||||||
|
if ( alias_name != name )
|
||||||
|
more.emplace(alias_name, false);
|
||||||
|
|
||||||
|
for ( ; ; )
|
||||||
|
{
|
||||||
|
auto prev_size = more.size();
|
||||||
|
|
||||||
|
for ( auto& [alias_name, checked] : more )
|
||||||
|
{
|
||||||
|
if ( checked ) continue;
|
||||||
|
|
||||||
|
for ( const auto& alias_alias : rval[alias_name] )
|
||||||
|
more.emplace(alias_alias, false);
|
||||||
|
|
||||||
|
checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( prev_size == more.size() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const auto& [alias_name, checked] : more )
|
||||||
|
rval[name].emplace(alias_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
%%}
|
||||||
|
|
||||||
|
## Returns all type name aliases of a value or type.
|
||||||
|
##
|
||||||
|
## x: An arbitrary value or type.
|
||||||
|
##
|
||||||
|
## Returns: The set of all type name aliases of *x* (or the type of *x*
|
||||||
|
## if it's a value instead of a type). For primitive values
|
||||||
|
## and types like :zeek:type:`string` or :zeek:type:`count`,
|
||||||
|
## this returns an empty set. For types with user-defined
|
||||||
|
## names like :zeek:type:`record` or :zeek:type:`enum`, the
|
||||||
|
## returned set contains the original user-defined name for the
|
||||||
|
## type along with all aliases. For other compound types, like
|
||||||
|
## :zeek:type:`table`, the returned set is empty unless
|
||||||
|
## explicitly requesting aliases for a user-defined type alias
|
||||||
|
## or a value that was explicitly created using a type alias
|
||||||
|
## (as opposed to originating from an "anonymous" constructor
|
||||||
|
## or initializer for that compound type).
|
||||||
|
function type_aliases%(x: any%): string_set
|
||||||
|
%{
|
||||||
|
auto rval = make_intrusive<zeek::TableVal>(zeek::id::string_set);
|
||||||
|
|
||||||
|
auto t = x->GetType();
|
||||||
|
|
||||||
|
if ( t->Tag() == TYPE_TYPE )
|
||||||
|
t = t->AsTypeType()->GetType();
|
||||||
|
|
||||||
|
const auto& tname = t->GetName();
|
||||||
|
|
||||||
|
if ( tname.empty() )
|
||||||
|
return rval;
|
||||||
|
|
||||||
|
static auto all_aliases = build_complete_alias_map();
|
||||||
|
auto it = all_aliases.find(tname);
|
||||||
|
|
||||||
|
if ( it == all_aliases.end() )
|
||||||
|
return rval;
|
||||||
|
|
||||||
|
for ( const auto& name : it->second )
|
||||||
|
rval->Assign(make_intrusive<zeek::StringVal>(name), nullptr);
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
%}
|
||||||
|
|
||||||
|
## Returns all value names associated with an enum type.
|
||||||
|
##
|
||||||
|
## et: An enum type.
|
||||||
|
##
|
||||||
|
## Returns: All enum value names associated with enum type *et*.
|
||||||
|
## If *et* is not an enum type, an empty set is returned.
|
||||||
|
function enum_names%(et: any%): string_set
|
||||||
|
%{
|
||||||
|
auto rval = make_intrusive<zeek::TableVal>(zeek::id::string_set);
|
||||||
|
|
||||||
|
if ( et->GetType()->Tag() != TYPE_TYPE )
|
||||||
|
return rval;
|
||||||
|
|
||||||
|
const auto& t = et->GetType()->AsTypeType()->GetType();
|
||||||
|
|
||||||
|
if ( t->Tag() != TYPE_ENUM )
|
||||||
|
return rval;
|
||||||
|
|
||||||
|
auto enum_type = t->AsEnumType();
|
||||||
|
|
||||||
|
for ( const auto& [name, i] : enum_type->Names() )
|
||||||
|
rval->Assign(make_intrusive<zeek::StringVal>(name), nullptr);
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
%}
|
||||||
|
|
||||||
## Returns: list of command-line arguments (``argv``) used to run Zeek.
|
## Returns: list of command-line arguments (``argv``) used to run Zeek.
|
||||||
function zeek_args%(%): string_vec
|
function zeek_args%(%): string_vec
|
||||||
%{
|
%{
|
||||||
|
@ -1983,6 +2102,13 @@ function lookup_ID%(id: string%) : any
|
||||||
if ( ! i )
|
if ( ! i )
|
||||||
return zeek::make_intrusive<zeek::StringVal>("<unknown id>");
|
return zeek::make_intrusive<zeek::StringVal>("<unknown id>");
|
||||||
|
|
||||||
|
if ( i->IsEnumConst() )
|
||||||
|
{
|
||||||
|
auto et = i->GetType()->AsEnumType();
|
||||||
|
auto idx = et->Lookup(detail::GLOBAL_MODULE_NAME, i->Name());
|
||||||
|
return et->GetEnumVal(idx);
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! i->GetVal() )
|
if ( ! i->GetVal() )
|
||||||
return zeek::make_intrusive<zeek::StringVal>("<no ID value>");
|
return zeek::make_intrusive<zeek::StringVal>("<no ID value>");
|
||||||
|
|
||||||
|
|
13
testing/btest/Baseline/bifs.enum_names/out
Normal file
13
testing/btest/Baseline/bifs.enum_names/out
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
{
|
||||||
|
RED,
|
||||||
|
GREEN,
|
||||||
|
PURPLE,
|
||||||
|
BLUE
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RED,
|
||||||
|
GREEN,
|
||||||
|
PURPLE,
|
||||||
|
BLUE
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
zeek test
|
zeek test
|
||||||
<unknown id>
|
<unknown id>
|
||||||
<unknown id>
|
<unknown id>
|
||||||
<unknown id>
|
<unknown id>
|
||||||
|
GREEN
|
||||||
event()
|
event()
|
||||||
|
|
22
testing/btest/Baseline/bifs.type_aliases/out
Normal file
22
testing/btest/Baseline/bifs.type_aliases/out
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
type aliases for 'RED enum val': ColorAlias Color
|
||||||
|
type aliases for 'Color enum type': ColorAlias Color
|
||||||
|
type aliases for 'MyRec val': MyRec MyRecAlias
|
||||||
|
type aliases for 'MyRecAlias val': MyRec MyRecAlias
|
||||||
|
type aliases for 'MyRec type': MyRec MyRecAlias
|
||||||
|
type aliases for 'MyRecalias type': MyRec MyRecAlias
|
||||||
|
type aliases for 'MyString val': it's just a 'string'
|
||||||
|
type aliases for 'MyString type': MyString AnotherString
|
||||||
|
type aliases for 'MyOtherString type': MyOtherString
|
||||||
|
type aliases for 'AnotherString type': MyString AnotherString
|
||||||
|
type aliases for 'string literal value': it's just a 'string'
|
||||||
|
type aliases for 'count literal value': it's just a 'count'
|
||||||
|
type aliases for 'MyTable value': MyTable2 MyTable3 MyTable MyTable4
|
||||||
|
type aliases for 'MyTable2 value': MyTable2 MyTable3 MyTable MyTable4
|
||||||
|
type aliases for 'MyTable3 value': MyTable2 MyTable3 MyTable MyTable4
|
||||||
|
type aliases for 'MyTable4 value': MyTable2 MyTable3 MyTable MyTable4
|
||||||
|
type aliases for 'MyTable type': MyTable2 MyTable3 MyTable MyTable4
|
||||||
|
type aliases for 'MyTable2 type': MyTable2 MyTable3 MyTable MyTable4
|
||||||
|
type aliases for 'MyTable3 type': MyTable2 MyTable3 MyTable MyTable4
|
||||||
|
type aliases for 'MyTable4 type': MyTable2 MyTable3 MyTable MyTable4
|
||||||
|
type aliases for 'table value': it's just a 'table[count] of string'
|
10
testing/btest/bifs/enum_names.zeek
Normal file
10
testing/btest/bifs/enum_names.zeek
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# @TEST-EXEC: zeek -b %INPUT >out
|
||||||
|
# @TEST-EXEC: btest-diff out
|
||||||
|
|
||||||
|
type Color: enum { RED, GREEN, BLUE };
|
||||||
|
type ColorAlias: Color;
|
||||||
|
|
||||||
|
redef enum Color += { PURPLE };
|
||||||
|
|
||||||
|
print enum_names(Color);
|
||||||
|
print enum_names(ColorAlias);
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
global a = "zeek test";
|
global a = "zeek test";
|
||||||
|
|
||||||
|
type Color: enum { RED, GREEN, BLUE };
|
||||||
|
|
||||||
event zeek_init()
|
event zeek_init()
|
||||||
{
|
{
|
||||||
local b = "local value";
|
local b = "local value";
|
||||||
|
@ -12,5 +14,6 @@ event zeek_init()
|
||||||
print lookup_ID("");
|
print lookup_ID("");
|
||||||
print lookup_ID("xyz");
|
print lookup_ID("xyz");
|
||||||
print lookup_ID("b");
|
print lookup_ID("b");
|
||||||
|
print lookup_ID("GREEN");
|
||||||
print type_name( lookup_ID("zeek_init") );
|
print type_name( lookup_ID("zeek_init") );
|
||||||
}
|
}
|
||||||
|
|
60
testing/btest/bifs/type_aliases.zeek
Normal file
60
testing/btest/bifs/type_aliases.zeek
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
# @TEST-EXEC: zeek -b %INPUT >out
|
||||||
|
# @TEST-EXEC: btest-diff out
|
||||||
|
|
||||||
|
type MyRec: record {
|
||||||
|
a: bool &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Color: enum { RED, GREEN, BLUE };
|
||||||
|
type ColorAlias: Color;
|
||||||
|
|
||||||
|
type MyRecAlias: MyRec;
|
||||||
|
type MyString: string;
|
||||||
|
type MyOtherString: string;
|
||||||
|
type AnotherString: MyString;
|
||||||
|
type MyTable: table[count] of string;
|
||||||
|
type MyTable2: MyTable;
|
||||||
|
type MyTable3: MyTable2;
|
||||||
|
type MyTable4: MyTable3;
|
||||||
|
|
||||||
|
function type_alias_list(label: string, x: any): string
|
||||||
|
{
|
||||||
|
local rval = fmt("type aliases for '%s':", label);
|
||||||
|
local aliases = type_aliases(x);
|
||||||
|
|
||||||
|
if ( |aliases| == 0 )
|
||||||
|
rval += fmt(" it's just a '%s'", type_name(x));
|
||||||
|
else
|
||||||
|
for ( a in aliases )
|
||||||
|
rval += fmt(" %s", a);
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
print type_alias_list("RED enum val", RED);
|
||||||
|
print type_alias_list("Color enum type", Color);
|
||||||
|
|
||||||
|
print type_alias_list("MyRec val", MyRec());
|
||||||
|
print type_alias_list("MyRecAlias val", MyRecAlias());
|
||||||
|
|
||||||
|
print type_alias_list("MyRec type", MyRec);
|
||||||
|
print type_alias_list("MyRecalias type", MyRecAlias);
|
||||||
|
|
||||||
|
local mys: MyString = "hi";
|
||||||
|
print type_alias_list("MyString val", mys);
|
||||||
|
print type_alias_list("MyString type", MyString);
|
||||||
|
print type_alias_list("MyOtherString type", MyOtherString);
|
||||||
|
print type_alias_list("AnotherString type", AnotherString);
|
||||||
|
|
||||||
|
print type_alias_list("string literal value", "test");
|
||||||
|
print type_alias_list("count literal value", 7);
|
||||||
|
|
||||||
|
print type_alias_list("MyTable value", MyTable([1] = "one", [2] = "two"));
|
||||||
|
print type_alias_list("MyTable2 value", MyTable2([1] = "one", [2] = "two"));
|
||||||
|
print type_alias_list("MyTable3 value", MyTable3([1] = "one", [2] = "two"));
|
||||||
|
print type_alias_list("MyTable4 value", MyTable4([1] = "one", [2] = "two"));
|
||||||
|
print type_alias_list("MyTable type", MyTable);
|
||||||
|
print type_alias_list("MyTable2 type", MyTable2);
|
||||||
|
print type_alias_list("MyTable3 type", MyTable3);
|
||||||
|
print type_alias_list("MyTable4 type", MyTable4);
|
||||||
|
print type_alias_list("table value", table([1] = "one", [2] = "two"));
|
Loading…
Add table
Add a link
Reference in a new issue