Skip to content

Commit

Permalink
Migrate Attribute::Kind to enum stringification framework.
Browse files Browse the repository at this point in the history
This patch performs cleans up the recently added `Attribute::Kind` enum
so it is properly integrated.

- introduce a standalone enum `attribute::Kind` outside of the
  `Attribute` class
- use enum helpers for conversion from and to string

Closes #1936.
  • Loading branch information
bbannier committed Jan 8, 2025
1 parent 789b223 commit 2fced3e
Show file tree
Hide file tree
Showing 31 changed files with 476 additions and 485 deletions.
229 changes: 118 additions & 111 deletions hilti/toolchain/include/ast/attribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,126 @@
#pragma once

#include <algorithm>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <utility>

#include <hilti/ast/expression.h>
#include <hilti/ast/forward.h>
#include <hilti/ast/node.h>
#include <hilti/base/util.h>

namespace hilti {

namespace attribute {

enum class Kind {
Eod,
Until,
UntilIncluding,
ParseAt,
ParseFrom,
Size,
MaxSize,
IPv4,
IPv6,
Type,
Count,
Synchronize,
Default,
Anonymous,
Internal,
Optional,
Static,
NoEmit,
OnHeap,
Nosub,
Cxxname,
HavePrototype,
Priority,
Convert,
While,
Requires,
ByteOrder,
BitOrder,
Chunked,
Originator,
Responder,
Try,
NeededByFeature,
RequiresTypeFeature,
AlwaysEmit,
Transient,
Anchor,

// Hooks
Debug,
Error,
Foreach,
};

namespace detail {
constexpr util::enum_::Value<Kind> AttributeKinds[] = {
{Kind::Eod, "&eod"},
{Kind::Until, "&until"},
{Kind::UntilIncluding, "&until-including"},
{Kind::ParseAt, "&parse-at"},
{Kind::ParseFrom, "&parse-from"},
{Kind::Size, "&size"},
{Kind::MaxSize, "&max-size"},
{Kind::IPv4, "&ipv4"},
{Kind::IPv6, "&ipv6"},
{Kind::Type, "&type"},
{Kind::Count, "&count"},
{Kind::Synchronize, "&synchronize"},
{Kind::Default, "&default"},
{Kind::Anonymous, "&anonymous"},
{Kind::Internal, "&internal"},
{Kind::Optional, "&optional"},
{Kind::Static, "&static"},
{Kind::NoEmit, "&no-emit"},
{Kind::OnHeap, "&on-heap"},
{Kind::Nosub, "&nosub"},
{Kind::Cxxname, "&cxxname"},
{Kind::HavePrototype, "&have_prototype"},
{Kind::Priority, "&priority"},
{Kind::Convert, "&convert"},
{Kind::While, "&while"},
{Kind::Requires, "&requires"},
{Kind::ByteOrder, "&byte-order"},
{Kind::BitOrder, "&bit-order"},
{Kind::Chunked, "&chunked"},
{Kind::Originator, "&originator"},
{Kind::Responder, "&responder"},
{Kind::Try, "&try"},
{Kind::NeededByFeature, "&needed-by-feature"},
{Kind::RequiresTypeFeature, "&requires-type-feature"},
{Kind::AlwaysEmit, "&always-emit"},
{Kind::Transient, "&transient"},
{Kind::Anchor, "&anchor"},
{Kind::Debug, "%debug"},
{Kind::Error, "%error"},
{Kind::Foreach, "foreach"},
};
}

constexpr auto to_string(Kind kind) { return util::enum_::to_string(kind, detail::AttributeKinds); }

/** Returns whether `kind` is in `kinds` */
inline bool isOneOf(Kind kind, std::initializer_list<Kind> kinds) {
return std::find(kinds.begin(), kinds.end(), kind) != kinds.end();
}

namespace kind {
constexpr auto from_string(const std::string_view& s) { return util::enum_::from_string(s, detail::AttributeKinds); }
} // namespace kind

} // namespace attribute

/** AST node for an attribute. */
class Attribute : public Node {
public:
enum class Kind {
Eod,
Until,
UntilIncluding,
ParseAt,
ParseFrom,
Size,
MaxSize,
IPv4,
IPv6,
Type,
Count,
Synchronize,
Default,
Anonymous,
Internal,
Optional,
Static,
NoEmit,
OnHeap,
Nosub,
Cxxname,
HavePrototype,
Priority,
Convert,
While,
Requires,
ByteOrder,
BitOrder,
Chunked,
Originator,
Responder,
Try,
NeededByFeature,
RequiresTypeFeature,
AlwaysEmit,
Transient,
Anchor,

// Hooks
Debug,
Error,
Foreach,
};

/** Returns the kind of the attribute, derived from its tag. */
const auto& kind() const { return _kind; }

Expand Down Expand Up @@ -114,22 +175,8 @@ class Attribute : public Node {
*/
Result<bool> coerceValueTo(Builder* builder, QualifiedType* dst);

/** Returns whether `kind` is in `kinds` */
static bool isOneOf(Kind kind, std::initializer_list<Kind> kinds) {
return std::find(kinds.begin(), kinds.end(), kind) != kinds.end();
}

/** Transforms a tag name into the appropriate enum value. */
static std::optional<Kind> tagToKind(std::string_view tag);

/** Transforms a kind into its name for diagnostics. */
static std::string_view kindToString(Kind kind);

/** A non-static alternative to get an attribute's string representation. */
std::string_view attributeName() const { return kindToString(_kind); }

node::Properties properties() const final {
auto p = node::Properties{{"tag", std::string{attributeName()}}};
auto p = node::Properties{{"tag", to_string(kind())}};
return Node::properties() + std::move(p);
}

Expand All @@ -141,7 +188,7 @@ class Attribute : public Node {
* @param v node representing the argument to associate with the attribute; must be an expression
* @param m meta data to associate with the node
*/
static auto create(ASTContext* ctx, Kind kind, Expression* v, const Meta& m = Meta()) {
static auto create(ASTContext* ctx, attribute::Kind kind, Expression* v, const Meta& m = Meta()) {
return ctx->make<Attribute>(ctx, {v}, kind, m);
}

Expand All @@ -151,60 +198,20 @@ class Attribute : public Node {
* @param kind the attribute's internal representation
* @param m meta data to associate with the node
*/
static auto create(ASTContext* ctx, Kind kind, const Meta& m = Meta()) { return create(ctx, kind, nullptr, m); }
static auto create(ASTContext* ctx, attribute::Kind kind, const Meta& m = Meta()) {
return create(ctx, kind, nullptr, m);
}

protected:
Attribute(ASTContext* ctx, Nodes children, Kind kind, Meta m = Meta())
Attribute(ASTContext* ctx, Nodes children, attribute::Kind kind, Meta m = Meta())
: Node(ctx, NodeTags, std::move(children), std::move(m)), _kind(kind) {}

std::string _dump() const override;

HILTI_NODE_0(Attribute, final);

private:
Kind _kind;
static inline std::map<std::string_view, Kind> _attr_map{
{"&eod", Attribute::Kind::Eod},
{"&until", Attribute::Kind::Until},
{"&until-including", Attribute::Kind::UntilIncluding},
{"&parse-at", Attribute::Kind::ParseAt},
{"&parse-from", Attribute::Kind::ParseFrom},
{"&size", Attribute::Kind::Size},
{"&max-size", Attribute::Kind::MaxSize},
{"&ipv4", Attribute::Kind::IPv4},
{"&ipv6", Attribute::Kind::IPv6},
{"&type", Attribute::Kind::Type},
{"&count", Attribute::Kind::Count},
{"&synchronize", Attribute::Kind::Synchronize},
{"&default", Attribute::Kind::Default},
{"&anonymous", Attribute::Kind::Anonymous},
{"&internal", Attribute::Kind::Internal},
{"&optional", Attribute::Kind::Optional},
{"&static", Attribute::Kind::Static},
{"&no-emit", Attribute::Kind::NoEmit},
{"&on-heap", Attribute::Kind::OnHeap},
{"&nosub", Attribute::Kind::Nosub},
{"&cxxname", Attribute::Kind::Cxxname},
{"&have_prototype", Attribute::Kind::HavePrototype},
{"&priority", Attribute::Kind::Priority},
{"&convert", Attribute::Kind::Convert},
{"&while", Attribute::Kind::While},
{"&requires", Attribute::Kind::Requires},
{"&byte-order", Attribute::Kind::ByteOrder},
{"&bit-order", Attribute::Kind::BitOrder},
{"&chunked", Attribute::Kind::Chunked},
{"&originator", Attribute::Kind::Originator},
{"&responder", Attribute::Kind::Responder},
{"&try", Attribute::Kind::Try},
{"&needed-by-feature", Attribute::Kind::NeededByFeature},
{"&requires-type-feature", Attribute::Kind::RequiresTypeFeature},
{"&always-emit", Attribute::Kind::AlwaysEmit},
{"&transient", Attribute::Kind::Transient},
{"&anchor", Attribute::Kind::Anchor},
{"%debug", Attribute::Kind::Debug},
{"%error", Attribute::Kind::Error},
{"foreach", Attribute::Kind::Foreach},
};
attribute::Kind _kind;
};

/** AST node holding a set of `Attribute` nodes. */
Expand All @@ -219,21 +226,21 @@ class AttributeSet : public Node {
*
* @return attribute if found
*/
Attribute* find(Attribute::Kind kind) const;
Attribute* find(attribute::Kind kind) const;

/**
* Retrieves all attributes with a given kind from the set.
*
* @return all attributes with matching kind
*/
hilti::node::Set<Attribute> findAll(Attribute::Kind kind) const;
hilti::node::Set<Attribute> findAll(attribute::Kind kind) const;

/**
* Returns true if there's an attribute with a given kind in the set.
*
* @param true if found
*/
bool has(Attribute::Kind kind) const { return find(kind) != nullptr; }
bool has(attribute::Kind kind) const { return find(kind) != nullptr; }

/** Adds an attribute to the set. */
void add(ASTContext* ctx, Attribute* a) {
Expand All @@ -243,7 +250,7 @@ class AttributeSet : public Node {
}

/** Removes all attributes of the given kind. */
void remove(Attribute::Kind kind);
void remove(attribute::Kind kind);

/** Returns true if the set has at least one element. */
operator bool() const { return ! attributes().empty(); }
Expand Down
4 changes: 2 additions & 2 deletions hilti/toolchain/include/ast/builder/node-factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ class NodeFactory {
/** Returns the AST context in use for creating nodes. */
ASTContext* context() const { return _context; }

auto attribute(hilti::Attribute::Kind kind, Expression* v, const Meta& m = Meta()) {
auto attribute(hilti::attribute::Kind kind, Expression* v, const Meta& m = Meta()) {
return hilti::Attribute::create(context(), kind, v, m);
}
auto attribute(hilti::Attribute::Kind kind, const Meta& m = Meta()) {
auto attribute(hilti::attribute::Kind kind, const Meta& m = Meta()) {
return hilti::Attribute::create(context(), kind, m);
}
auto attributeSet(Attributes attrs = {}, Meta m = Meta()) {
Expand Down
2 changes: 1 addition & 1 deletion hilti/toolchain/include/ast/ctors/regexp.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class RegExp : public Ctor {
/**
* Returns true if this pattern does not need support for capturing groups.
*/
bool isNoSub() const { return attributes()->find(hilti::Attribute::Kind::Nosub) != nullptr; }
bool isNoSub() const { return attributes()->find(hilti::attribute::Kind::Nosub) != nullptr; }

QualifiedType* type() const final { return child<QualifiedType>(0); }

Expand Down
14 changes: 7 additions & 7 deletions hilti/toolchain/include/ast/declarations/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ class Field : public Declaration {
}

hilti::Expression* default_() const {
if ( auto a = attributes()->find(hilti::Attribute::Kind::Default) )
if ( auto a = attributes()->find(hilti::attribute::Kind::Default) )
return *a->valueAsExpression();
else
return {};
}

auto isAnonymous() const { return attributes()->find(hilti::Attribute::Kind::Anonymous) != nullptr; }
auto isInternal() const { return attributes()->find(hilti::Attribute::Kind::Internal) != nullptr; }
auto isOptional() const { return attributes()->find(hilti::Attribute::Kind::Optional) != nullptr; }
auto isStatic() const { return attributes()->find(hilti::Attribute::Kind::Static) != nullptr; }
auto isNoEmit() const { return attributes()->find(hilti::Attribute::Kind::NoEmit) != nullptr; }
auto isAnonymous() const { return attributes()->find(hilti::attribute::Kind::Anonymous) != nullptr; }
auto isInternal() const { return attributes()->find(hilti::attribute::Kind::Internal) != nullptr; }
auto isOptional() const { return attributes()->find(hilti::attribute::Kind::Optional) != nullptr; }
auto isStatic() const { return attributes()->find(hilti::attribute::Kind::Static) != nullptr; }
auto isNoEmit() const { return attributes()->find(hilti::attribute::Kind::NoEmit) != nullptr; }

auto linkedTypeIndex() const { return _linked_type_index; }

Expand All @@ -78,7 +78,7 @@ class Field : public Declaration {
if ( ! attrs )
attrs = AttributeSet::create(ctx);

if ( attrs->has(hilti::Attribute::Kind::Static) )
if ( attrs->has(hilti::attribute::Kind::Static) )
// make it assignable
type = type->recreateAsLhs(ctx);

Expand Down
2 changes: 1 addition & 1 deletion hilti/toolchain/include/ast/declarations/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Type : public Declaration {

bool isOnHeap() const {
if ( auto x = attributes() )
return x->find(hilti::Attribute::Kind::OnHeap) != nullptr;
return x->find(hilti::attribute::Kind::OnHeap) != nullptr;
else
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion hilti/toolchain/include/ast/function.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class Function : public Node {
auto body() const { return child<Statement>(1); }
auto attributes() const { return child<AttributeSet>(2); }
auto callingConvention() const { return _cc; }
auto isStatic() const { return attributes()->find(hilti::Attribute::Kind::Static) != nullptr; }
auto isStatic() const { return attributes()->find(hilti::attribute::Kind::Static) != nullptr; }

void setBody(ASTContext* ctx, Statement* b) { setChild(ctx, 1, b); }
void setID(ID id) { _id = std::move(id); }
Expand Down
Loading

0 comments on commit 2fced3e

Please sign in to comment.