Spicy
unit.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <functional>
6 #include <memory>
7 #include <set>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 #include <hilti/rt/filesystem.h>
13 
14 #include <hilti/ast/id.h>
15 #include <hilti/ast/module.h>
16 #include <hilti/base/logger.h>
17 #include <hilti/base/result.h>
18 #include <hilti/base/util.h>
19 #include <hilti/compiler/context.h>
20 #include <hilti/compiler/detail/cxx/unit.h>
21 #include <hilti/compiler/jit.h>
22 
23 namespace hilti {
24 namespace linker {
33 using MetaData = detail::cxx::linker::MetaData;
34 } // namespace linker
35 
43 class Unit {
44 public:
47  assert(_id);
48  return NodeRef(imported(_id));
49  }
50 
55  auto id() const { return _id; }
56 
61  auto path() const { return _path; }
62 
67  Result<Nothing> compile();
68 
70  Result<Nothing> codegen();
71 
80  Result<Nothing> print(std::ostream& out) const;
81 
90  Result<Nothing> createPrototypes(std::ostream& out);
91 
98  Result<CxxCode> cxxCode() const;
99 
120  Result<context::ModuleIndex> import(const ID& id, const hilti::rt::filesystem::path& ext,
121  std::optional<ID> scope = {},
122  std::vector<hilti::rt::filesystem::path> search_dirs = {});
123 
135  Result<context::ModuleIndex> import(const hilti::rt::filesystem::path& path);
136 
144  Node& imported(const ID& id) const;
145 
151  std::set<context::ModuleIndex> allImported(bool code_only = false) const;
152 
161  if ( auto x = _lookupModule(id) )
162  return x->requires_compilation;
163 
164  return result::Error("unknown module");
165  }
166 
173  if ( _cxx_unit )
174  return _cxx_unit->linkerMetaData();
175 
176  return result::Error("no C++ code compiled");
177  }
178 
184  bool isCompiledHILTI() const { return _have_hilti_ast; }
185 
187  std::shared_ptr<Context> context() const { return _context; }
188 
190  const Options& options() const { return _context->options(); }
191 
204  static Result<Unit> fromModule(const std::shared_ptr<Context>& context, hilti::Module&& module,
205  const hilti::rt::filesystem::path& path = "");
206 
217  static Result<Unit> fromSource(const std::shared_ptr<Context>& context, const hilti::rt::filesystem::path& path);
218 
227  static Result<Unit> fromCache(const std::shared_ptr<Context>& context, const hilti::ID& id);
228 
237  static Result<Unit> fromCache(const std::shared_ptr<Context>& context, const hilti::rt::filesystem::path& path);
238 
246  static Result<Unit> fromCXX(std::shared_ptr<Context> context, detail::cxx::Unit cxx,
247  const hilti::rt::filesystem::path& path = "");
248 
259  static Result<Unit> link(const std::shared_ptr<Context>& context, const std::vector<linker::MetaData>& mds);
260 
277  static std::pair<bool, std::optional<linker::MetaData>> readLinkerMetaData(
278  std::istream& input, const hilti::rt::filesystem::path& path = "<input stream>");
279 
280 private:
281  // Private constructor initializing the unit's meta data. Note that the
282  // corresponding module must then be imported into the unit as well.
283  // Normally you'd use the static ``Unit::from*()`` functions to do that
284  // while creating a unit.
285  Unit(std::shared_ptr<Context> context, ID id, hilti::rt::filesystem::path path, bool have_hilti_ast)
286  : _context(std::move(context)), _id(std::move(id)), _path(std::move(path)), _have_hilti_ast(have_hilti_ast) {}
287 
288  // Returns a list of all currently known/imported modules.
289  std::vector<std::pair<ID, NodeRef>> _currentModules() const;
290 
291  // Looks up a module by its ID. The module must have been imported into
292  // the unit to succeed. Assuming so, it returns the context's cache entry
293  // for the module.
294  std::optional<context::CachedModule> _lookupModule(const ID& id) const;
295 
296  // Backend for the public import() methods.
297  Result<context::ModuleIndex> _import(const hilti::rt::filesystem::path& path, std::optional<ID> expected_name);
298 
299  // Runs a validation pass on a set of modules and reports any errors.
300  bool _validateASTs(std::vector<std::pair<ID, NodeRef>>& modules,
301  const std::function<bool(const ID&, NodeRef&)>& run_hooks_callback);
302 
303  // Runs a validation pass on a module and reports any errors.
304  bool _validateAST(const ID& id, NodeRef module, const std::function<bool(const ID&, NodeRef&)>& run_hooks_callback);
305 
306  // Runs a validation pass on a set of nodes and reports any errors.
307  bool _validateASTs(const ID& id, std::vector<Node>& nodes,
308  const std::function<bool(const ID&, std::vector<Node>&)>& run_hooks_callback);
309  // Updates the requires_compilation flags for all of a module's imports.
310  void _determineCompilationRequirements(const Node& module);
311  // Sends a debug dump of a module's AST to the global logger.
312  void _dumpAST(const Node& module, const logging::DebugStream& stream, const std::string& prefix, int round = 0);
313  // Sends a debug dump of all modules parsed so far to the global logger.
314  void _dumpASTs(const logging::DebugStream& stream, const std::string& prefix, int round = 0);
315  // Sends a debug dump of a module's AST to an output stream.
316  void _dumpAST(const Node& module, std::ostream& stream, const std::string& prefix, int round = 0);
317  // Sends a debug dump of all modules parsed so far to an output stream.
318  void _dumpASTs(std::ostream& stream, const std::string& prefix, int round = 0);
319  // Records a debug dump of all modules parsed so far to disk.
320  void _saveIterationASTs(const std::string& prefix, int round = 0);
321  // Clear any previously computed AST state before beginning a pass over the AST.
322  void _resetNodes(const ID& id, Node* root);
323 
324  // Parses a source file with the appropriate plugin.
325  static Result<hilti::Module> parse(const std::shared_ptr<Context>& context,
326  const hilti::rt::filesystem::path& path);
327 
328  std::shared_ptr<Context> _context; // global context
329  ID _id; // ID of top-level module being compiled by this unit
330  hilti::rt::filesystem::path _path; // path of top-level module being compiled by this unit
331  bool _have_hilti_ast; // true if the top-level module comes with a HILTI AST (normally the case, but not for the
332  // linker's C++ code)
333  std::set<ID> _modules; // set of all module ASTs this unit has parsed and processed (inc. imported ones)
334  std::optional<detail::cxx::Unit> _cxx_unit; // compiled C++ code for this unit, once available
335 };
336 
337 } // namespace hilti
Definition: result.h:18
Definition: context.h:32
const Options & options() const
Definition: unit.h:190
bool isCompiledHILTI() const
Definition: unit.h:184
NodeRef module()
Definition: unit.h:46
auto id() const
Definition: unit.h:55
Definition: unit.h:68
Result< linker::MetaData > linkerMetaData() const
Definition: unit.h:172
auto path() const
Definition: unit.h:61
std::shared_ptr< Context > context() const
Definition: unit.h:187
Definition: unit.h:43
Definition: module.h:20
Definition: node.h:97
Result< bool > requiresCompilation(const ID &id)
Definition: unit.h:160
Definition: node_ref.h:44
Definition: id.h:18
Definition: result.h:67
Definition: logger.h:28