14 #include <unordered_set>
18 #include <hilti/ast/doc-string.h>
19 #include <hilti/ast/forward.h>
20 #include <hilti/ast/id.h>
21 #include <hilti/ast/meta.h>
22 #include <hilti/ast/node-range.h>
23 #include <hilti/ast/node-tag.h>
24 #include <hilti/ast/scope.h>
25 #include <hilti/ast/visitor-dispatcher.h>
27 #define __HILTI_NODE_COMMON_final(NS, CLASS) \
28 ::hilti::Node* _clone(::hilti::ASTContext* ctx) const final { return ctx->make<CLASS>(*this); }
30 #define __HILTI_NODE_COMMON_override(NS, CLASS)
32 #define __HILTI_NODE_COMMON(NS, CLASS, override_) \
33 friend class ::NS::builder::NodeBuilder; \
34 friend class hilti::ASTContext; \
35 friend class hilti::Node; \
36 std::string _typename() const override { return hilti::util::typename_(*this); } \
37 __HILTI_NODE_COMMON_##override_(NS, CLASS)
39 #define __HILTI_NODE_0(NS, CLASS, override_) \
40 __HILTI_NODE_COMMON(NS, CLASS, override_) \
42 static constexpr uint16_t NodeLevel = 1; \
43 static constexpr ::hilti::node::Tag NodeTag = ::hilti::node::tag::CLASS; \
44 static constexpr ::hilti::node::Tags NodeTags = {::hilti::node::tag::Node, ::hilti::node::tag::CLASS};
46 #define HILTI_NODE_0(CLASS, override_) \
47 __HILTI_NODE_0(hilti, CLASS, override_) \
49 void dispatch(::hilti::visitor::Dispatcher& v) override_ { \
50 v(static_cast<::hilti::Node*>(this)); \
54 #define __HILTI_NODE_1(NS, CLASS, BASE, override_) \
55 __HILTI_NODE_COMMON(NS, CLASS, override_) \
57 static constexpr uint16_t NodeLevel = 2; \
58 static constexpr ::hilti::node::Tag NodeTag = ::hilti::node::tag::CLASS; \
59 static constexpr ::hilti::node::Tags NodeTags = {::hilti::node::tag::Node, \
60 ::hilti::node::tag::BASE, \
61 ::hilti::node::tag::CLASS};
63 #define HILTI_NODE_1(CLASS, BASE, override_) \
64 __HILTI_NODE_1(hilti, CLASS, BASE, override_) \
66 void dispatch(::hilti::visitor::Dispatcher& v) override_ { \
67 v(static_cast<::hilti::Node*>(this)); \
68 v(static_cast<BASE*>(this)); \
72 #define __HILTI_NODE_2(NS, CLASS, BASE1, BASE2, override_) \
73 __HILTI_NODE_COMMON(NS, CLASS, override_) \
75 static constexpr uint16_t NodeLevel = 3; \
76 static constexpr ::hilti::node::Tag NodeTag = ::hilti::node::tag::CLASS; \
77 static constexpr ::hilti::node::Tags NodeTags = {::hilti::node::tag::Node, \
78 ::hilti::node::tag::BASE2, \
79 ::hilti::node::tag::BASE1, \
80 ::hilti::node::tag::CLASS};
82 #define HILTI_NODE_2(CLASS, BASE1, BASE2, override_) \
83 __HILTI_NODE_2(hilti, CLASS, BASE1, BASE2, override_) \
85 void dispatch(::hilti::visitor::Dispatcher& v) override_ { \
86 v(static_cast<::hilti::Node*>(this)); \
87 v(static_cast<BASE1*>(this)); \
88 v(static_cast<BASE2*>(this)); \
101 Node* deepcopy(ASTContext* ctx, Node* n,
bool force);
114 T* deepcopy(ASTContext* ctx, T* n,
bool force =
false) {
118 return detail::deepcopy(ctx, n, force)->template as<T>();
122 using PropertyValue = std::
123 variant<bool, const char*, double, int, int64_t, unsigned int, uint64_t, std::string, ID, std::optional<uint64_t>>;
126 inline std::string to_string(
const PropertyValue& v) {
128 auto operator()(
bool s) {
return std::string(s ?
"true" :
"false"); }
129 auto operator()(
const char* s) {
return util::escapeUTF8(s); }
130 auto operator()(
double d) {
return util::fmt(
"%.6f", d); }
131 auto operator()(
int i) {
return util::fmt(
"%d", i); }
132 auto operator()(int64_t i) {
return util::fmt(
"%" PRId64, i); }
133 auto operator()(
const std::string& s) {
return util::escapeUTF8(s); }
134 auto operator()(
const ID&
id) {
return id.str(); }
135 auto operator()(
const std::optional<uint64_t>& u) {
return u ? util::fmt(
"%" PRIu64, *u) :
"<not set>"; }
136 auto operator()(
unsigned int u) {
return util::fmt(
"%u", u); }
137 auto operator()(uint64_t u) {
return util::fmt(
"%" PRIu64, u); }
140 return std::visit(Visitor(), v);
144 enum class ErrorPriority {
151 inline bool operator<(ErrorPriority x, ErrorPriority y) {
152 return static_cast<std::underlying_type_t<ErrorPriority>
>(x) <
153 static_cast<std::underlying_type_t<ErrorPriority>
>(y);
165 bool operator<(
const Error& other)
const {
175 using Properties = std::map<std::string, node::PropertyValue>;
185 other._node =
nullptr;
192 if (
this == &other )
202 if (
this == &other )
207 other._node =
nullptr;
217 T* operator->()
const {
return _node; }
218 T& operator*()
const {
return *_node; }
219 explicit operator bool()
const {
return _node !=
nullptr; }
220 operator T*()
const {
return _node; }
222 T* get()
const {
return _node; }
250 for (
auto _node_tag : std::ranges::reverse_view(_node_tags) ) {
251 if ( _node_tag != 0 )
272 for ( ; p && i > 1; i-- )
288 else if ( _parent->
isA_<T>() )
289 return static_cast<T*
>(_parent);
291 return _parent->
parent<T>();
300 template<
typename... Args>
301 bool pathMatches()
const {
302 const Node* current =
this;
304 current = current->parent();
305 return current && current->isA<Args>();
317 for (
auto* n =
parent(); n; i++, n = n->parent() )
324 const auto&
meta()
const {
return *_meta; }
327 const auto&
location()
const {
return _meta->location(); }
336 auto scope()
const {
return _scope.get(); }
345 _scope = std::make_unique<Scope>();
395 i =
static_cast<int>(_children.size()) + i;
397 if ( std::cmp_greater_equal(i, _children.size()) )
400 return _children[i] ? _children[i]->as<T>() :
nullptr;
414 i =
static_cast<int>(_children.size()) + i;
416 if ( std::cmp_greater_equal(i, _children.size()) )
419 return _children[i] ? _children[i]->tryAs<T>() :
nullptr;
431 i =
static_cast<int>(_children.size()) + i;
433 if ( std::cmp_greater_equal(i, _children.size()) )
450 auto children(
int begin, std::optional<int> end)
const {
451 end = _normalizeEndIndex(begin, end);
470 end = _normalizeEndIndex(begin, end);
485 typename hilti::node::Set<T> n;
486 for (
auto c = _children.begin(); c != _children.end(); c = std::next(c) ) {
490 if (
auto t = (*c)->tryAs<T>() )
507 if ( std::ranges::find(_children, n) != _children.end() )
513 for (
const auto* c : _children ) {
514 if ( c && c->hasChild(n, recurse) )
529 auto i = std::ranges::find(_children, n);
530 if ( i == _children.end() )
534 if ( ++i == _children.end() )
553 _children.emplace_back(
nullptr);
557 n = _newChild(ctx, n);
559 if ( ! n->
location() && _meta && _meta->location() )
562 _children.emplace_back(n);
589 if (
auto i = std::ranges::find(_children, n); i != _children.end() ) {
590 (*i)->_parent =
nullptr;
605 end = _normalizeEndIndex(begin, end);
609 auto end_ = _children.begin() + *end;
610 for (
auto i = _children.begin() + begin; i < end_; i++ ) {
612 (*i)->_parent =
nullptr;
617 _children.erase(_children.begin() + begin, end_);
632 if (
auto* old = _children[idx] ) {
633 old->_parent =
nullptr;
638 _children[idx] =
nullptr;
642 n = _newChild(ctx, n);
646 if ( ! n->
location() && _meta->location() )
664 i =
static_cast<int>(_children.size()) + i;
666 if ( std::cmp_greater_equal(i, _children.size()) )
669 auto* old = _children[i];
670 old->_parent =
nullptr;
672 _children[i] =
nullptr;
712 _checkCast<T>(
false);
714 return (T::NodeLevel < _node_tags.size() && T::NodeTag == _node_tags[T::NodeLevel]);
725 return (T::NodeLevel < _node_tags.size() && T::NodeTag == _node_tags[T::NodeLevel]);
737 return static_cast<const T*
>(
this);
751 return static_cast<T*
>(
this);
761 _checkCast<T>(
false);
765 return static_cast<const T*
>(
this);
777 _checkCast<T>(
false);
780 return static_cast<T*
>(
this);
795 return static_cast<T*
>(
this);
812 void print(std::ostream& out,
bool compact,
bool user_visible)
const;
821 std::string
print()
const;
836 operator std::string()
const {
return print(); }
842 std::string
dump()
const;
851 std::string
renderSelf(
bool include_location =
true)
const;
861 void addError(std::string msg, std::vector<std::string> context = {}) {
874 void addError(std::string msg, node::ErrorPriority priority, std::vector<std::string> context = {}) {
887 addError(std::move(msg),
location(), node::ErrorPriority::Normal, std::move(context));
898 void addError(std::string msg,
Location l, node::ErrorPriority priority, std::vector<std::string> context = {}) {
900 error.message = std::move(msg);
901 error.location = std::move(l);
902 error.context = std::move(context);
903 error.priority = priority;
906 _errors = std::make_unique<std::vector<node::Error>>();
908 _errors->emplace_back(std::move(error));
912 bool hasErrors()
const {
return _errors && ! _errors->empty(); }
916 static std::vector<node::Error> no_errors;
917 return _errors ? *_errors : no_errors;
931 assert(_ref_count != -1);
940 assert(_ref_count != -1);
941 assert(_ref_count > 0);
965 virtual std::string_view
branchTag()
const {
return ""; }
967 Node& operator=(
const Node& other) =
delete;
968 Node& operator=(
Node&& other) noexcept =
delete;
970 static constexpr uint16_t NodeLevel = 0;
971 static constexpr ::hilti::node::Tag NodeTag = ::hilti::node::tag::Node;
972 static constexpr ::hilti::node::Tags NodeTags = {::hilti::node::tag::Node};
985 : _node_tags(node_tags), _meta(
Meta::get(std::move(
meta))) {
986 assert(! _node_tags.empty());
990 c = _newChild(ctx, c);
991 assert(! c->_parent);
996 _children.push_back(c);
1002 : _node_tags(node_tags), _meta(
Meta::get(std::move(
meta))) {
1003 assert(! _node_tags.empty());
1015 Node(
const Node& other) : _node_tags(other._node_tags) {
1016 _meta = other._meta;
1031 virtual std::string
_typename()
const {
return util::typename_(*
this); }
1045 virtual std::string
_dump()
const {
return ""; }
1055 std::optional<int> _normalizeEndIndex(
int begin, std::optional<int> end)
const {
1056 if ( end && *end < 0 )
1057 end =
static_cast<int>(_children.size()) + *end;
1060 end =
static_cast<int>(_children.size());
1073 template<
typename T>
1074 void _checkCast(
bool enforce_success)
const {
1077 auto ours = (T::NodeLevel < _node_tags.size() && T::NodeTag == _node_tags[T::NodeLevel]);
1078 auto theirs = (
dynamic_cast<const T*
>(
this) !=
nullptr);
1080 if ( ours != theirs ) {
1081 std::cerr << util::fmt(
"internal error: Node::_checkCast() RTTI mismatch\n")
1082 << util::fmt(
"isA<T=%s>(%s) -> %s but dynamic_cast() says %s\n",
1085 ours ?
"true" :
"false",
1086 theirs ?
"true" :
"false")
1087 << util::fmt(
"T::type_level=%" PRIu16
" T::node_tags={%s} this->types={%s}\n",
1089 node::to_string(T::NodeTags),
1090 node::to_string(_node_tags));
1094 if ( enforce_success && ! ours ) {
1095 std::cerr << util::fmt(
"internal error: unexpected type, want %s but have %s\n",
1096 util::typename_<T>(),
1106 if ( std::is_base_of_v<UnqualifiedType, T> && ! std::is_same_v<UnqualifiedType, T> )
1107 _checkCastBackend();
1112 void _checkCastBackend()
const;
1114 const node::Tags _node_tags;
1115 int64_t _ref_count = 0;
1117 Node* _parent =
nullptr;
1121 std::unique_ptr<Scope> _scope =
nullptr;
1122 std::unique_ptr<std::vector<node::Error>> _errors;
1124 static uint64_t _instances;
1125 uint64_t _identity = _instances++;
1143 node::Properties
properties()
const {
return {{
"unique_id", _id}}; }
1161 WithUniqueID(
const char* prefix) : _id(util::fmt(
"%s_%" PRIu64, prefix, _id_counter++)) {}
1166 inline static uint64_t _id_counter = 0;
1181 _doc = std::move(doc);
1187 std::optional<DocString> _doc;
1193 void recordSeen(
const Node* n) { _seen.insert(n); }
1194 bool haveSeen(
const Node* n)
const {
return _seen.contains(n); }
1195 void clear() { _seen.clear(); }
1198 std::unordered_set<const Node*> _seen;
1205 template<
typename T>
1206 Nodes flatten(std::vector<T> t) {
1208 v.reserve(t.size());
1209 for (
auto it = std::make_move_iterator(t.begin()); it != std::make_move_iterator(t.end()); ++it )
1210 v.emplace_back(*it);
1219 template<
typename T>
1222 v.reserve(t.size());
1223 for (
const auto& i : t )
1224 v.emplace_back(std::move(i));
1230 template<
typename T = Node*>
1231 inline Nodes flatten(Node* n) {
1236 template<
typename T>
1237 inline Nodes flatten(T* n) {
1238 return {std::move(n)};
1242 template<
typename T = std::
nullptr_t>
1243 inline Nodes flatten(std::nullptr_t) {
1248 inline Nodes flatten() {
return Nodes(); }
1254 template<
typename T,
typename... Ts>
1255 Nodes flatten(T t, Ts... ts)
1256 requires(0 !=
sizeof...(Ts))
1258 return util::concat(std::move(flatten(std::move(t))), flatten(std::move(ts)...));
1264 inline std::ostream& operator<<(std::ostream& out,
const Node& n) {
1265 n.print(out,
true,
true);
1271 inline hilti::node::Properties operator+(hilti::node::Properties p1, hilti::node::Properties p2) {
1272 p1.merge(std::move(p2));
1276 template<
typename T>
Definition: ast-context.h:128
Definition: doc-string.h:15
Definition: location.h:17
Node * sibling(Node *n) const
Definition: node.h:528
T * parent() const
Definition: node.h:285
std::string renderSelf(bool include_location=true) const
Definition: node.cc:42
void clearScope()
Definition: node.h:354
T * tryAs_()
Definition: node.h:793
const T * tryAs() const
Definition: node.h:759
const auto & errors() const
Definition: node.h:915
void addError(std::string msg, std::vector< std::string > context={})
Definition: node.h:861
void setMeta(Meta m)
Definition: node.h:330
Node * clearChild(int i)
Definition: node.h:662
T * tryAs()
Definition: node.h:775
auto pathLength() const
Definition: node.h:315
T * as() const
Definition: node.h:733
bool hasErrors() const
Definition: node.h:912
bool isA_() const
Definition: node.h:724
auto children(int begin, std::optional< int > end) const
Definition: node.h:450
std::string print() const
Definition: node.cc:102
virtual Node * _clone(ASTContext *ctx) const =0
T * as()
Definition: node.h:747
Node * parent(int i=1) const
Definition: node.h:267
node::Tag nodeTag() const
Definition: node.h:248
void setChild(ASTContext *ctx, size_t idx, Node *n)
Definition: node.h:631
Node * removeFromParent()
Definition: node.cc:125
Node(const Node &other)
Definition: node.h:1015
void addError(std::string msg, const Location &, std::vector< std::string > context={})
Definition: node.h:886
void clearErrors()
Definition: node.h:921
void addChild(ASTContext *ctx, Node *n)
Definition: node.h:551
void removeChild(Node *n)
Definition: node.h:585
virtual std::string _typename() const
Definition: node.h:1031
void addError(std::string msg, Location l, node::ErrorPriority priority, std::vector< std::string > context={})
Definition: node.h:898
virtual bool inheritScope() const
Definition: node.h:370
auto children(int begin, std::optional< int > end)
Definition: node.h:469
const auto & location() const
Definition: node.h:327
Node * child(int i) const
Definition: node.h:429
void release()
Definition: node.h:939
auto scope() const
Definition: node.h:336
const auto & children() const
Definition: node.h:382
auto getOrCreateScope()
Definition: node.h:343
virtual std::string_view branchTag() const
Definition: node.h:965
void replaceChild(ASTContext *ctx, Node *old, Node *new_)
Definition: node.cc:114
void addError(std::string msg, node::ErrorPriority priority, std::vector< std::string > context={})
Definition: node.h:874
uint64_t identity() const
Definition: node.h:379
void replaceChildren(ASTContext *ctx, const Nodes &children)
Definition: node.cc:134
const auto & meta() const
Definition: node.h:324
bool hasChild(const Node *n, bool recurse=false) const
Definition: node.h:503
T * childTryAs(int i) const
Definition: node.h:412
virtual std::string _dump() const
Definition: node.h:1045
Node(ASTContext *ctx, node::Tags node_tags, Nodes children, Meta meta)
Definition: node.h:984
void removeChildren(int begin, std::optional< int > end)
Definition: node.h:604
bool isRetained() const
Definition: node.h:946
node::Set< T > childrenOfType() const
Definition: node.h:484
std::string printRaw() const
Definition: node.cc:108
std::string dump() const
Definition: node.cc:35
void clearChildren()
Definition: node.cc:141
bool hasParent() const
Definition: node.h:259
virtual node::Properties properties() const
Definition: node.h:953
virtual void dispatch(visitor::Dispatcher &v)=0
void addChildren(ASTContext *ctx, const Nodes &children)
Definition: node.h:574
T * child(int i) const
Definition: node.h:393
Node(ASTContext *, node::Tags node_tags, Meta meta)
Definition: node.h:1001
bool isA() const
Definition: node.h:710
void retain()
Definition: node.h:930
Result< std::pair< Declaration *, ID > > lookupID(const ID &id, const std::string_view &what) const
Definition: node.cc:227
std::string typename_() const
Definition: node.h:376
Definition: forward.h:757
Definition: node-range.h:92
void clearDocumentation()
Definition: node.h:1176
const std::optional< DocString > & documentation() const
Definition: node.h:1173
void setDocumentation(DocString doc)
Definition: node.h:1179
ID uniqueID() const
Definition: node.h:1140
node::Properties properties() const
Definition: node.h:1143
WithUniqueID(const char *prefix)
Definition: node.h:1161
Definition: visitor-dispatcher.h:9
std::string message
Definition: node.h:158
ErrorPriority priority
Definition: node.h:161
Location location
Definition: node.h:159
std::vector< std::string > context
Definition: node.h:160