brewery
notashelf /
4ea090cf330d87b264b6d554a8307347c46f7e56

nixir

public

Import-resolving Nix IR plugin

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.git
src/irc/resolver.cppCpp114 lines3.0 KB
1
#include "resolver.h"
2
#include "parser.h"
3
#include <filesystem>
4
#include <fstream>
5
#include <iostream>
6
#include <regex>
7
#include <sstream>
8
9
namespace nix_irc {
10
11
namespace fs = std::filesystem;
12
13
struct Resolver::Impl {
14
  ResolverConfig config;
15
  std::vector<std::pair<std::string, std::string>> resolved_imports;
16
  std::unordered_set<std::string> visited;
17
  Parser parser;
18
19
  Impl(const ResolverConfig& cfg) : config(cfg) {}
20
21
  std::string resolve_path(const std::string& path, const std::string& from_file) {
22
    fs::path p(path);
23
24
    if (p.is_absolute()) {
25
      if (fs::exists(p))
26
        return path;
27
      return "";
28
    }
29
30
    fs::path from_dir = fs::path(from_file).parent_path();
31
    fs::path candidate = from_dir / p;
32
    if (fs::exists(candidate))
33
      return candidate.string();
34
35
    for (const auto& search : config.search_paths) {
36
      candidate = fs::path(search) / p;
37
      if (fs::exists(candidate))
38
        return candidate.string();
39
    }
40
41
    return "";
42
  }
43
44
  ImportResult do_resolve(const std::string& path, const std::string& from_file) {
45
    std::string resolved = resolve_path(path, from_file);
46
47
    if (resolved.empty()) {
48
      return {false, "", "Cannot find file: " + path, nullptr};
49
    }
50
51
    if (visited.count(resolved)) {
52
      return {true, resolved, "", nullptr};
53
    }
54
    visited.insert(resolved);
55
56
    try {
57
      auto ast = parser.parse_file(resolved);
58
      return {true, resolved, "", ast};
59
    } catch (const std::exception& e) {
60
      return {false, "", e.what(), nullptr};
61
    }
62
  }
63
};
64
65
Resolver::Resolver(const ResolverConfig& config) : pImpl(std::make_unique<Impl>(config)) {}
66
Resolver::~Resolver() = default;
67
68
void Resolver::add_search_path(const std::string& path) {
69
  pImpl->config.search_paths.push_back(path);
70
}
71
72
void Resolver::set_search_paths(const std::vector<std::string>& paths) {
73
  pImpl->config.search_paths = paths;
74
}
75
76
ImportResult Resolver::resolve_import(const std::string& path, const std::string& from_file) {
77
  auto result = pImpl->do_resolve(path, from_file);
78
  if (result.success && result.ast) {
79
    pImpl->resolved_imports.push_back({path, result.path});
80
  }
81
  return result;
82
}
83
84
ImportResult Resolver::resolve_import(const Node& import_node, const std::string& from_file) {
85
  const ConstPathNode* path_node = import_node.get_if<ConstPathNode>();
86
  if (!path_node) {
87
    return {false, "", "Dynamic import not supported", nullptr};
88
  }
89
  return resolve_import(path_node->value, from_file);
90
}
91
92
std::vector<std::string> Resolver::get_resolved_files() const {
93
  std::vector<std::string> files;
94
  for (const auto& [orig, resolved] : pImpl->resolved_imports) {
95
    (void) orig;
96
    files.push_back(resolved);
97
  }
98
  return files;
99
}
100
101
std::vector<std::pair<std::string, std::string>> Resolver::get_imports() const {
102
  return pImpl->resolved_imports;
103
}
104
105
bool is_static_import(const Node& node) {
106
  return node.holds<ConstPathNode>();
107
}
108
109
std::string normalize_path(const std::string& path) {
110
  fs::path p(path);
111
  return fs::absolute(p).string();
112
}
113
114
} // namespace nix_irc