Spicy
ast-context.h
1 // Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <map>
6 #include <memory>
7 #include <set>
8 #include <string>
9 #include <unordered_map>
10 #include <utility>
11 #include <vector>
12 
13 #include <hilti/rt/types/integer.h>
14 
15 #include <hilti/ast/declarations/module-uid.h>
16 #include <hilti/ast/forward.h>
17 #include <hilti/ast/node.h>
18 #include <hilti/base/logger.h>
19 #include <hilti/base/uniquer.h>
20 
21 namespace hilti {
22 
23 class ASTContext;
24 class Context;
25 class Driver;
26 struct Plugin;
27 
28 namespace type {
29 struct Wildcard;
30 }
31 
41 Result<declaration::Module*> parseSource(Builder* builder, std::istream& in, const std::string& filename);
42 
43 namespace ast {
44 
45 namespace detail {
46 
47 class DependencyTracker;
48 
53 template<char Prefix>
54 class ContextIndex {
55 public:
62  explicit ContextIndex(size_t index = 0) : _value(index) {}
63 
65  auto value() const { return _value; }
66 
71  auto str() const { return _value > 0 ? std::string(1, Prefix) + rt::to_string(_value) : std::string("-"); }
72 
74  explicit operator bool() const { return *this != None; }
75 
76  bool operator==(const ContextIndex& other) const { return _value == other._value; }
77  bool operator!=(const ContextIndex& other) const { return _value != other._value; }
78 
79  ContextIndex(const ContextIndex& other) = default;
80  ContextIndex(ContextIndex&& other) noexcept = default;
81  ContextIndex& operator=(const ContextIndex& other) = default;
82  ContextIndex& operator=(ContextIndex&& other) noexcept = default;
83 
84  inline static const ContextIndex None{0};
86 private:
87  rt::integer::safe<uint32_t> _value = 0; // safe integer to catch any uint32_t overflows
88 };
89 
90 template<char Prefix>
91 inline std::string to_string(const hilti::ast::detail::ContextIndex<Prefix>& index) {
92  return index.str();
93 }
94 
95 template<char Prefix>
96 inline std::ostream& operator<<(std::ostream& out, const hilti::ast::detail::ContextIndex<Prefix>& index) {
97  return out << index.str();
98 }
99 
100 // Helper to sort declaration pointers by their canonical IDs.
102  bool operator()(const Declaration* a, const Declaration* b) const;
103 };
104 
105 } // namespace detail
106 
109 
112 
113 } // namespace ast
114 
121 class ASTContext : public std::enable_shared_from_this<ASTContext> {
122 public:
123  // Set of declarations ordered by their canonical IDs.
124  using DeclarationSet = std::set<Declaration*, ast::detail::DeclarationPtrCmp>;
125 
131  ASTContext(Context* context);
132 
134  ~ASTContext();
135 
137  auto* compilerContext() const { return _context; }
138 
140  auto root() const { return _root.get(); }
141 
157  Result<declaration::module::UID> parseSource(Builder* builder, const hilti::rt::filesystem::path& path,
158  std::optional<hilti::rt::filesystem::path> process_extension = {});
159 
179  Result<declaration::module::UID> importModule(Builder* builder, const ID& id, const ID& scope,
180  const hilti::rt::filesystem::path& parse_extension,
181  const std::optional<hilti::rt::filesystem::path>& process_extension,
182  std::vector<hilti::rt::filesystem::path> search_dirs);
183 
185  declaration::Module* newModule(Builder* builder, ID id, const hilti::rt::filesystem::path& process_extension);
186 
194  if ( auto m = _modules_by_uid.find(uid); m != _modules_by_uid.end() )
195  return m->second;
196  else
197  return nullptr;
198  }
199 
210 
215  Driver* driver() const { return _driver; }
216 
228  std::set<declaration::module::UID> dependencies(const declaration::module::UID& uid, bool recursive = false) const;
229 
249  const DeclarationSet& dependentDeclarations(Declaration* n);
250 
263  void updateModuleUID(const declaration::module::UID& old_uid, const declaration::module::UID& new_uid);
264 
282 
290  Declaration* lookup(ast::DeclarationIndex index); // must exists, otherwise internal error -> result is not null
291 
307  void replace(Declaration* old, Declaration* new_);
308 
322 
331 
343  void replace(UnqualifiedType* old, UnqualifiedType* new_);
344 
349  ID uniqueCanononicalID(const ID& id) { return _canon_id_uniquer.get(id, false); }
350 
357  void dump(const hilti::logging::DebugStream& stream, const std::string& prefix);
358 
365  template<typename T, typename... Args>
366  T* make(Args&&... args) {
367  auto t = new T(std::forward<Args>(args)...);
368  _nodes.emplace_back(std::unique_ptr<Node>(t));
369  return t;
370  }
371 
383  template<typename T, typename... Args>
384  T* make(ASTContext* ctx, std::initializer_list<Node*> children, Args&&... args) {
385  assert(ctx == this);
386  auto t = new T(ctx, children, std::forward<Args>(args)...);
387  _nodes.emplace_back(std::unique_ptr<Node>(t));
388  return t;
389  }
390 
403  template<typename T, typename... Args>
404  T* make(ASTContext* ctx, type::Wildcard&& wildcard, std::initializer_list<Node*> children, Args&&... args) {
405  assert(ctx == this);
406  auto t = new T(ctx, std::forward<type::Wildcard>(wildcard), children, std::forward<Args>(args)...);
407  _nodes.emplace_back(std::unique_ptr<Node>(t));
408  return t;
409  }
410 
412  void garbageCollect();
413 
415  void clear();
416 
417 private:
418  // The following methods implement the corresponding phases of AST processing.
419 
420  Result<declaration::module::UID> _parseSource(Builder* builder, const hilti::rt::filesystem::path& path,
421  const ID& scope,
422  std::optional<hilti::rt::filesystem::path> process_extension = {});
423  Result<Nothing> _init(Builder* builder, const Plugin& plugin);
424  Result<Nothing> _buildScopes(Builder* builder, const Plugin& plugin);
425  Result<Nothing> _clearState(Builder* builder, const Plugin& plugin);
426  Result<Nothing> _resolve(Builder* builder, const Plugin& plugin);
427  Result<Nothing> _resolveUnresolvedNodes(bool* modified, Builder* builder, const Plugin& plugin);
428  Result<Nothing> _resolveRoot(bool* modified, Builder* builder, const Plugin& plugin);
429  Result<Nothing> _validate(Builder* builder, const Plugin& plugin, bool pre_resolver);
430  Result<Nothing> _transform(Builder* builder, const Plugin& plugin);
431  Result<Nothing> _collectErrors();
432  Result<Nothing> _optimize(Builder* builder);
433  Result<Nothing> _computeDependencies();
434 
435  // Adds a module to the AST. The module must not be part of any AST yet
436  // (including the current one).
437  declaration::module::UID _addModuleToAST(declaration::Module* module);
438 
439  // Performs internal consistency checks on the AST. Meant to execute only
440  // in debug builds as it may affect performance.
441  void _checkAST(bool finished) const;
442 
443  // Dumps the AST to disk during AST processing, for debugging..
444  void _saveIterationAST(const Plugin& plugin, const std::string& prefix, int round = 0);
445 
446  // Dumps the AST to disk during AST processing, for debugging..
447  void _saveIterationAST(const Plugin& plugin, const std::string& prefix, const std::string& tag);
448 
449  // Dumps the AST to a debugging stream.
450  void _dumpAST(const hilti::logging::DebugStream& stream, const Plugin& plugin, const std::string& prefix,
451  int round);
452 
453  // Dumps the AST to a debugging stream.
454  void _dumpAST(std::ostream& stream, const Plugin& plugin, const std::string& prefix, int round);
455 
456  // Dumps the accumulated state tables of the context to a debugging stream.
457  void _dumpState(const logging::DebugStream& stream);
458 
459  // Dump statistics about the AST to a debugging stream.
460  void _dumpStats(const logging::DebugStream& stream, std::string_view tag);
461 
462  // Dumps the accumulated state tables of the context to a debugging stream.
463  void _dumpDeclarations(const logging::DebugStream& stream, const Plugin& plugin);
464 
465  Context* _context = nullptr; // compiler context
466  std::vector<std::unique_ptr<Node>> _nodes; // all nodes allocated through the context; used by garbage collection
467 
468  node::RetainedPtr<ASTRoot> _root = nullptr; // root node of the AST
469  bool _resolved = false; // true if `processAST()` has finished successfully
470  Driver* _driver = nullptr; // pointer to compiler drive during `processAST()`, null outside of that
471  util::Uniquer<ID> _canon_id_uniquer; // Produces unique canonified IDs
472  std::unique_ptr<ast::detail::DependencyTracker> _dependency_tracker; // records dependencies between declarations
473 
474  uint64_t _total_rounds = 0; // total number of rounds of AST processing
475 
476  std::unordered_map<declaration::module::UID, node::RetainedPtr<declaration::Module>>
477  _modules_by_uid; // all known modules indexed by UID
478 
479  std::unordered_map<std::string, declaration::Module*>
480  _modules_by_path; // all known modules indexed by path (retained by _by_uid)
481  std::map<std::pair<ID, ID>, declaration::Module*>
482  _modules_by_id_and_scope; // all known modules indexed by their ID and search scope (retained by _by_uid)
483 
484  std::vector<node::RetainedPtr<Declaration>>
485  _declarations_by_index; // all registered declarations; vector position corresponds to their index
486  std::vector<node::RetainedPtr<UnqualifiedType>>
487  _types_by_index; // all registered types; vector position corresponds to their index
488 };
489 
494 class ASTRoot : public Node {
495 public:
496  static auto create(ASTContext* ctx) { return ctx->make<ASTRoot>(ctx); }
497 
498 protected:
499  ASTRoot(ASTContext* ctx) : Node(ctx, NodeTags, {}, Meta(Location("<root>"))) {}
500 
501  std::string _dump() const final;
502 
503  HILTI_NODE_0(ASTRoot, final);
504 };
505 
506 } // namespace hilti
507 
508 namespace std {
509 template<char Prefix>
510 struct hash<hilti::ast::detail::ContextIndex<Prefix>> {
511  size_t operator()(hilti::ast::detail::ContextIndex<Prefix> x) const { return x.value().Ref(); }
512 };
513 } // namespace std
Definition: ast-context.h:121
ASTContext(Context *context)
Definition: ast-context.cc:212
~ASTContext()
Definition: ast-context.cc:219
auto root() const
Definition: ast-context.h:140
T * make(ASTContext *ctx, std::initializer_list< Node * > children, Args &&... args)
Definition: ast-context.h:384
void updateModuleUID(const declaration::module::UID &old_uid, const declaration::module::UID &new_uid)
Definition: ast-context.cc:392
std::set< declaration::module::UID > dependencies(const declaration::module::UID &uid, bool recursive=false) const
Driver * driver() const
Definition: ast-context.h:215
ast::DeclarationIndex register_(Declaration *decl)
Definition: ast-context.cc:408
ID uniqueCanononicalID(const ID &id)
Definition: ast-context.h:349
void clear()
Definition: ast-context.cc:232
auto * compilerContext() const
Definition: ast-context.h:137
T * make(Args &&... args)
Definition: ast-context.h:366
declaration::Module * newModule(Builder *builder, ID id, const hilti::rt::filesystem::path &process_extension)
Definition: ast-context.cc:304
Result< declaration::module::UID > importModule(Builder *builder, const ID &id, const ID &scope, const hilti::rt::filesystem::path &parse_extension, const std::optional< hilti::rt::filesystem::path > &process_extension, std::vector< hilti::rt::filesystem::path > search_dirs)
Definition: ast-context.cc:255
void replace(Declaration *old, Declaration *new_)
Definition: ast-context.cc:434
Declaration * lookup(ast::DeclarationIndex index)
Definition: ast-context.cc:462
Result< declaration::module::UID > parseSource(Builder *builder, const hilti::rt::filesystem::path &path, std::optional< hilti::rt::filesystem::path > process_extension={})
Definition: ast-context.cc:250
T * make(ASTContext *ctx, type::Wildcard &&wildcard, std::initializer_list< Node * > children, Args &&... args)
Definition: ast-context.h:404
void garbageCollect()
Definition: ast-context.cc:312
const DeclarationSet & dependentDeclarations(Declaration *n)
Definition: ast-context.cc:967
Result< Nothing > processAST(Builder *builder, Driver *driver)
Definition: ast-context.cc:572
void dump(const hilti::logging::DebugStream &stream, const std::string &prefix)
Definition: ast-context.cc:846
declaration::Module * module(const declaration::module::UID &uid) const
Definition: ast-context.h:193
Definition: ast-context.h:494
std::string _dump() const final
Definition: ast-context.cc:210
Definition: builder.h:36
Definition: context.h:108
Definition: declaration.h:48
Definition: driver.h:85
Definition: id.h:15
Definition: location.h:17
Definition: meta.h:30
Definition: node.h:240
Node(ASTContext *ctx, node::Tags node_tags, Nodes children, Meta meta)
Definition: node.h:922
Definition: type.h:148
Definition: ast-context.h:54
auto str() const
Definition: ast-context.h:71
static const ContextIndex None
Definition: ast-context.h:84
ContextIndex(size_t index=0)
Definition: ast-context.h:62
auto value() const
Definition: ast-context.h:65
Definition: module.h:29
Definition: logger.h:28
Definition: node.h:176
Definition: result.h:71
std::string to_string(T &&x)
Definition: extension-points.h:26
Definition: ast-context.h:101
Definition: module-uid.h:20
Definition: type.h:38