Spicy
unit.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <unistd.h>
6 
7 #include <functional>
8 #include <memory>
9 #include <string>
10 #include <unordered_map>
11 #include <unordered_set>
12 #include <utility>
13 #include <vector>
14 
15 #include <hilti/rt/filesystem.h>
16 
17 #include <hilti/ast/id.h>
18 #include <hilti/ast/module.h>
19 #include <hilti/base/logger.h>
20 #include <hilti/base/result.h>
21 #include <hilti/base/util.h>
22 #include <hilti/compiler/context.h>
23 #include <hilti/compiler/detail/cxx/unit.h>
24 #include <hilti/compiler/jit.h>
25 
26 namespace hilti {
27 
28 struct Plugin;
29 
30 namespace linker {
39 using MetaData = detail::cxx::linker::MetaData;
40 } // namespace linker
41 
49 class Unit {
50 public:
52  ~Unit();
53 
55  NodeRef moduleRef() const { return _module ? NodeRef(*_module) : NodeRef(); }
56 
61  Node& module() {
62  assert(_module);
63  return *_module;
64  }
65 
70  const auto& cacheIndex() const { return _index; }
71 
73  const auto& id() const { return _index.id; }
74 
85  ID uniqueID() const { return _unique_id; }
86 
88  const auto& path() const { return _index.path; }
89 
96  const auto& extension() const { return _extension; }
97 
106  void setExtension(const hilti::rt::filesystem::path& ext) { _extension = ext; }
107 
108  enum ASTState { Modified, NotModified };
109 
111  void resetAST();
112 
119  Result<Nothing> buildASTScopes(const Plugin& plugin);
120 
128  Result<ASTState> resolveAST(const Plugin& plugin);
129 
136  bool validateASTPre(const Plugin& plugin);
137 
144  bool validateASTPost(const Plugin& plugin);
145 
152  Result<Nothing> transformAST(const Plugin& plugin);
153 
159  Result<Nothing> codegen();
160 
169  Result<Nothing> print(std::ostream& out) const;
170 
179  Result<Nothing> createPrototypes(std::ostream& out);
180 
187  Result<CxxCode> cxxCode() const;
188 
195  std::vector<std::weak_ptr<Unit>> dependencies(bool recursive = false) const;
196 
198  void clearDependencies() { _dependencies.clear(); };
199 
206  bool addDependency(const std::shared_ptr<Unit>& unit);
207 
214  if ( _cxx_unit )
215  return _cxx_unit->linkerMetaData();
216 
217  return result::Error("no C++ code compiled");
218  }
219 
225  bool isCompiledHILTI() const { return _module.has_value(); }
226 
232  bool requiresCompilation();
233 
238  void setRequiresCompilation() { _requires_compilation = true; }
239 
243  bool isResolved() { return _resolved; }
244 
251  void setResolved(bool resolved) { _resolved = resolved; }
252 
254  std::shared_ptr<Context> context() const { return _context.lock(); }
255 
257  const Options& options() const { return context()->options(); }
258 
273  static Result<std::shared_ptr<Unit>> fromSource(const std::shared_ptr<Context>& context,
274  const hilti::rt::filesystem::path& path,
275  const std::optional<ID>& scope,
276  std::optional<hilti::rt::filesystem::path> process_extension = {});
277 
291  static std::shared_ptr<Unit> fromModule(const std::shared_ptr<Context>& context, const hilti::Module& module,
292  hilti::rt::filesystem::path extension);
293 
309  static Result<std::shared_ptr<Unit>> fromImport(const std::shared_ptr<Context>& context, const ID& id,
310  const hilti::rt::filesystem::path& parse_extension,
311  const hilti::rt::filesystem::path& process_extension,
312  std::optional<ID> scope,
313  std::vector<hilti::rt::filesystem::path> search_dirs);
314 
324  static Result<std::shared_ptr<Unit>> fromCache(const std::shared_ptr<Context>& context,
325  const hilti::rt::filesystem::path& path,
326  const std::optional<ID>& scope);
327 
336  static Result<std::shared_ptr<Unit>> fromCXX(const std::shared_ptr<Context>& context, detail::cxx::Unit cxx,
337  const hilti::rt::filesystem::path& path = "");
338 
349  static Result<std::shared_ptr<Unit>> link(const std::shared_ptr<Context>& context,
350  const std::vector<linker::MetaData>& mds);
351 
368  static std::pair<bool, std::optional<linker::MetaData>> readLinkerMetaData(
369  std::istream& input, const hilti::rt::filesystem::path& path = "<input stream>");
370 
371 private:
372  // Private constructor initializing the unit's meta data. Use the public
373  // `from*()` factory functions instead to instantiate a unit.
374  Unit(const std::shared_ptr<Context>& context, const ID& id, const std::optional<ID>& scope,
375  const hilti::rt::filesystem::path& path, hilti::rt::filesystem::path extension, Node&& module)
376  : _index(id, scope, util::normalizePath(path)),
377  _unique_id(_makeUniqueID(id)),
378  _extension(std::move(std::move(extension))),
379  _module(std::move(module)),
380  _context(context) {}
381 
382  Unit(const std::shared_ptr<Context>& context, const ID& id, const std::optional<ID>& scope,
383  const hilti::rt::filesystem::path& path, hilti::rt::filesystem::path extension,
384  std::optional<detail::cxx::Unit> cxx_unit = {})
385  : _index(id, scope, util::normalizePath(path)),
386  _unique_id(_makeUniqueID(id)),
387  _extension(std::move(std::move(extension))),
388  _context(context),
389  _cxx_unit(std::move(cxx_unit)) {}
390 
391  // Make a given ID globally unique.
392  ID _makeUniqueID(const ID& id);
393 
394  // Backend for the public import() methods.
395  Result<context::CacheIndex> _import(const hilti::rt::filesystem::path& path, std::optional<ID> expected_name);
396 
397  // Reports any errors recorded in the AST to stderr.
398  //
399  // @returns false if there were errors, true if the AST is all good
400  bool _collectErrors();
401 
402  // Recursively destroys the module's AST.
403  void _destroyModule();
404 
405  // Helper for dependencies() to recurse.
406  void _recursiveDependencies(std::vector<std::weak_ptr<Unit>>* dst, std::unordered_set<const Unit*>* seen) const;
407 
408  // Parses a source file with the appropriate plugin.
409  static Result<hilti::Module> _parse(const std::shared_ptr<Context>& context,
410  const hilti::rt::filesystem::path& path);
411 
412  context::CacheIndex _index; // index for the context's module cache
413  ID _unique_id; // globally unique ID for this module
414  hilti::rt::filesystem::path _extension; // AST extension, which may differ from source file
415  std::optional<Node> _module; // root node for AST (always a `Module`), if available
416  std::vector<std::weak_ptr<Unit>> _dependencies; // recorded dependencies
417  std::weak_ptr<Context> _context; // global context
418  std::optional<detail::cxx::Unit> _cxx_unit; // compiled C++ code for this unit, once available
419  bool _resolved = false; // state of resolving the AST
420  bool _requires_compilation = false; // mark explicitly as requiring compilation to C++
421 
422  static std::unordered_map<ID, unsigned int> _uid_cache; // cache storing state for generating globally unique IDs
423 };
424 
425 } // namespace hilti
Definition: context.h:107
void setExtension(const hilti::rt::filesystem::path &ext)
Definition: unit.h:106
ID uniqueID() const
Definition: unit.h:85
Definition: result.h:18
Definition: context.h:33
const Options & options() const
Definition: unit.h:257
bool isCompiledHILTI() const
Definition: unit.h:225
bool isResolved()
Definition: unit.h:243
const auto & id() const
Definition: unit.h:73
Node & module()
Definition: unit.h:61
void setRequiresCompilation()
Definition: unit.h:238
NodeRef moduleRef() const
Definition: unit.h:55
Definition: unit.h:65
const auto & path() const
Definition: unit.h:88
Result< linker::MetaData > linkerMetaData() const
Definition: unit.h:213
Definition: plugin.h:52
const auto & cacheIndex() const
Definition: unit.h:70
std::shared_ptr< Context > context() const
Definition: unit.h:254
Definition: unit.h:49
Definition: module.h:21
Definition: node.h:112
Definition: node-ref.h:45
void clearDependencies()
Definition: unit.h:198
const auto & extension() const
Definition: unit.h:96
Definition: id.h:18
Definition: result.h:67
void setResolved(bool resolved)
Definition: unit.h:251