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_set>
11 #include <utility>
12 #include <vector>
13 
14 #include <hilti/rt/filesystem.h>
15 
16 #include <hilti/ast/id.h>
17 #include <hilti/ast/module.h>
18 #include <hilti/base/logger.h>
19 #include <hilti/base/result.h>
20 #include <hilti/base/util.h>
21 #include <hilti/compiler/context.h>
22 #include <hilti/compiler/detail/cxx/unit.h>
23 #include <hilti/compiler/jit.h>
24 
25 namespace hilti {
26 
27 struct Plugin;
28 
29 namespace linker {
38 using MetaData = detail::cxx::linker::MetaData;
39 } // namespace linker
40 
48 class Unit {
49 public:
51  ~Unit();
52 
54  NodeRef moduleRef() const { return _module ? NodeRef(*_module) : NodeRef(); }
55 
60  Node& module() {
61  assert(_module);
62  return *_module;
63  }
64 
69  const auto& cacheIndex() { return _index; }
70 
72  const auto& id() const { return _index.id; }
73 
75  const auto& path() const { return _index.path; }
76 
83  const auto& extension() const { return _extension; }
84 
93  void setExtension(const hilti::rt::filesystem::path& ext) { _extension = ext; }
94 
95  enum ASTState { Modified, NotModified };
96 
98  void resetAST();
99 
106  Result<Nothing> buildASTScopes(const Plugin& plugin);
107 
115  Result<ASTState> resolveAST(const Plugin& plugin);
116 
123  bool validateASTPre(const Plugin& plugin);
124 
131  bool validateASTPost(const Plugin& plugin);
132 
139  Result<Nothing> transformAST(const Plugin& plugin);
140 
146  Result<Nothing> codegen();
147 
156  Result<Nothing> print(std::ostream& out) const;
157 
166  Result<Nothing> createPrototypes(std::ostream& out);
167 
174  Result<CxxCode> cxxCode() const;
175 
182  std::vector<std::weak_ptr<Unit>> dependencies(bool recursive = false) const;
183 
185  void clearDependencies() { _dependencies.clear(); };
186 
193  bool addDependency(const std::shared_ptr<Unit>& unit);
194 
201  if ( _cxx_unit )
202  return _cxx_unit->linkerMetaData();
203 
204  return result::Error("no C++ code compiled");
205  }
206 
212  bool isCompiledHILTI() const { return _module.has_value(); }
213 
219  bool requiresCompilation();
220 
225  void setRequiresCompilation() { _requires_compilation = true; }
226 
230  bool isResolved() { return _resolved; }
231 
238  void setResolved(bool resolved) { _resolved = resolved; }
239 
241  std::shared_ptr<Context> context() const { return _context.lock(); }
242 
244  const Options& options() const { return context()->options(); }
245 
259  static Result<std::shared_ptr<Unit>> fromSource(const std::shared_ptr<Context>& context,
260  const hilti::rt::filesystem::path& path,
261  std::optional<hilti::rt::filesystem::path> process_extension = {});
262 
276  static std::shared_ptr<Unit> fromModule(const std::shared_ptr<Context>& context, hilti::Module module,
277  hilti::rt::filesystem::path extension);
278 
294  static Result<std::shared_ptr<Unit>> fromImport(const std::shared_ptr<Context>& context, const ID& id,
295  const hilti::rt::filesystem::path& parse_extension,
296  const hilti::rt::filesystem::path& process_extension,
297  std::optional<ID> scope,
298  std::vector<hilti::rt::filesystem::path> search_dirs);
299 
309  static Result<std::shared_ptr<Unit>> fromCache(const std::shared_ptr<Context>& context, const hilti::ID& id,
310  const hilti::rt::filesystem::path& extension);
311 
320  static Result<std::shared_ptr<Unit>> fromCache(const std::shared_ptr<Context>& context,
321  const hilti::rt::filesystem::path& path);
322 
331  static Result<std::shared_ptr<Unit>> fromCXX(std::shared_ptr<Context> context, detail::cxx::Unit cxx,
332  const hilti::rt::filesystem::path& path = "");
333 
344  static Result<std::shared_ptr<Unit>> link(const std::shared_ptr<Context>& context,
345  const std::vector<linker::MetaData>& mds);
346 
363  static std::pair<bool, std::optional<linker::MetaData>> readLinkerMetaData(
364  std::istream& input, const hilti::rt::filesystem::path& path = "<input stream>");
365 
366 private:
367  // Private constructor initializing the unit's meta data. Use the public
368  // `from*()` factory functions instead to instantiate a unit.
369  Unit(std::shared_ptr<Context> context, ID id, hilti::rt::filesystem::path path,
370  hilti::rt::filesystem::path extension, Node&& module)
371  : _index(id, util::normalizePath(path)),
372  _extension(extension),
373  _module(std::move(module)),
374  _context(std::move(context)) {}
375 
376  Unit(std::shared_ptr<Context> context, ID id, hilti::rt::filesystem::path path,
377  hilti::rt::filesystem::path extension, std::optional<detail::cxx::Unit> cxx_unit = {})
378  : _index(id, util::normalizePath(path)),
379  _extension(extension),
380  _context(std::move(context)),
381  _cxx_unit(std::move(cxx_unit)) {}
382 
383  // Backend for the public import() methods.
384  Result<context::CacheIndex> _import(const hilti::rt::filesystem::path& path, std::optional<ID> expected_name);
385 
386  // Reports any errors recorded in the AST to stderr.
387  //
388  // @returns false if there were errors, true if the AST is all good
389  bool _collectErrors();
390 
391  // Recursively destroys the module's AST.
392  void _destroyModule();
393 
394  // Helper for dependencies() to recurse.
395  void _recursiveDependencies(std::vector<std::weak_ptr<Unit>>* dst, std::unordered_set<const Unit*>* seen) const;
396 
397  // Parses a source file with the appropriate plugin.
398  static Result<hilti::Module> _parse(const std::shared_ptr<Context>& context,
399  const hilti::rt::filesystem::path& path);
400 
401  context::CacheIndex _index; // index for the context's module cache
402  hilti::rt::filesystem::path _extension; // AST extension, which may differ from source file
403  std::optional<Node> _module; // root node for AST (always a `Module`), if available
404  std::vector<std::weak_ptr<Unit>> _dependencies; // recorded dependencies
405  std::weak_ptr<Context> _context; // global context
406  std::optional<detail::cxx::Unit> _cxx_unit; // compiled C++ code for this unit, once available
407  bool _resolved = false; // state of resolving the AST
408  bool _requires_compilation = false; // mark explicitly as requiring compilation to C++
409 };
410 
411 } // namespace hilti
Definition: context.h:107
void setExtension(const hilti::rt::filesystem::path &ext)
Definition: unit.h:93
Definition: result.h:18
Definition: context.h:33
const Options & options() const
Definition: unit.h:244
bool isCompiledHILTI() const
Definition: unit.h:212
bool isResolved()
Definition: unit.h:230
const auto & id() const
Definition: unit.h:72
Node & module()
Definition: unit.h:60
void setRequiresCompilation()
Definition: unit.h:225
NodeRef moduleRef() const
Definition: unit.h:54
Definition: unit.h:68
const auto & path() const
Definition: unit.h:75
Result< linker::MetaData > linkerMetaData() const
Definition: unit.h:200
Definition: plugin.h:52
const auto & cacheIndex()
Definition: unit.h:69
std::shared_ptr< Context > context() const
Definition: unit.h:241
Definition: unit.h:48
Definition: module.h:21
Definition: node.h:113
Definition: node-ref.h:44
void clearDependencies()
Definition: unit.h:185
const auto & extension() const
Definition: unit.h:83
Definition: id.h:18
Definition: result.h:67
void setResolved(bool resolved)
Definition: unit.h:238