#pragma once | |||||
#include <dds/util.hpp> | |||||
#include <vector> | |||||
namespace dds { | |||||
struct archive_rules { | |||||
std::vector<fs::path> objects; | |||||
fs::path out; | |||||
}; | |||||
} // namespace dds |
#include <dds/proc.hpp> | #include <dds/proc.hpp> | ||||
#include <dds/source.hpp> | #include <dds/source.hpp> | ||||
#include <dds/toolchain.hpp> | #include <dds/toolchain.hpp> | ||||
#include <dds/lm_parse.hpp> | |||||
#include <libman/parse.hpp> | |||||
#include <algorithm> | #include <algorithm> | ||||
#include <chrono> | #include <chrono> | ||||
copy_headers(header_root, header_dest, sources); | copy_headers(header_root, header_dest, sources); | ||||
} | } | ||||
std::vector<lm_pair> lm_pairs; | |||||
std::vector<lm::pair> lm_pairs; | |||||
lm_pairs.emplace_back("Type", "Package"); | lm_pairs.emplace_back("Type", "Package"); | ||||
lm_pairs.emplace_back("Name", params.export_name); | lm_pairs.emplace_back("Name", params.export_name); | ||||
lm_pairs.emplace_back("Namespace", params.export_name); | lm_pairs.emplace_back("Namespace", params.export_name); | ||||
lm_pairs.emplace_back("Library", "lib.lml"); | lm_pairs.emplace_back("Library", "lib.lml"); | ||||
lm_write_pairs(export_root / "package.lmp", lm_pairs); | |||||
lm::write_pairs(export_root / "package.lmp", lm_pairs); | |||||
lm_pairs.clear(); | lm_pairs.clear(); | ||||
lm_pairs.emplace_back("Type", "Library"); | lm_pairs.emplace_back("Type", "Library"); | ||||
lm_pairs.emplace_back("Name", params.export_name); | lm_pairs.emplace_back("Name", params.export_name); | ||||
lm_pairs.emplace_back("Path", fs::relative(archive_dest, export_root).string()); | lm_pairs.emplace_back("Path", fs::relative(archive_dest, export_root).string()); | ||||
lm_pairs.emplace_back("Include-Path", fs::relative(header_dest, export_root).string()); | lm_pairs.emplace_back("Include-Path", fs::relative(header_dest, export_root).string()); | ||||
lm_write_pairs(export_root / "lib.lml", lm_pairs); | |||||
lm::write_pairs(export_root / "lib.lml", lm_pairs); | |||||
} | } | ||||
fs::path | fs::path |
#include <dds/build.hpp> | #include <dds/build.hpp> | ||||
#include <dds/lm_parse.hpp> | |||||
#include <libman/parse.hpp> | |||||
#include <dds/logging.hpp> | #include <dds/logging.hpp> | ||||
#include <dds/util.hpp> | #include <dds/util.hpp> | ||||
#include "./manifest.hpp" | #include "./manifest.hpp" | ||||
#include <dds/lm_parse.hpp> | |||||
#include <libman/parse.hpp> | |||||
#include <spdlog/fmt/fmt.h> | #include <spdlog/fmt/fmt.h> | ||||
using namespace dds; | using namespace dds; | ||||
library_manifest library_manifest::load_from_file(const fs::path& fpath) { | library_manifest library_manifest::load_from_file(const fs::path& fpath) { | ||||
auto kvs = lm_parse_file(fpath); | |||||
auto kvs = lm::parse_file(fpath); | |||||
library_manifest ret; | library_manifest ret; | ||||
for (auto& pair : kvs.items()) { | for (auto& pair : kvs.items()) { | ||||
if (pair.key() == "Private-Include") { | if (pair.key() == "Private-Include") { | ||||
ret.private_includes.emplace_back(pair.value()); | ret.private_includes.emplace_back(pair.value()); | ||||
} else if (pair.key() == "Private-Define") { | } else if (pair.key() == "Private-Define") { | ||||
ret.private_defines.emplace_back(pair.value()); | ret.private_defines.emplace_back(pair.value()); | ||||
} else if (pair.key() == "Uses") { | |||||
ret.uses.emplace_back(pair.value()); | |||||
} else if (pair.key() == "Links") { | |||||
ret.uses.emplace_back(pair.value()); | |||||
} else { | } else { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
fmt::format("Unknown key in file '{}': {}", fpath.string(), pair.key())); | fmt::format("Unknown key in file '{}': {}", fpath.string(), pair.key())); | ||||
} | } | ||||
} | } | ||||
return ret; | return ret; | ||||
} | |||||
} |
struct library_manifest { | struct library_manifest { | ||||
std::vector<fs::path> private_includes; | std::vector<fs::path> private_includes; | ||||
std::vector<std::string> private_defines; | std::vector<std::string> private_defines; | ||||
std::vector<std::string> uses; | |||||
std::vector<std::string> links; | |||||
static library_manifest load_from_file(const fs::path&); | static library_manifest load_from_file(const fs::path&); | ||||
}; | }; |
#include "./toolchain.hpp" | #include "./toolchain.hpp" | ||||
#include <dds/lm_parse.hpp> | |||||
#include <libman/parse.hpp> | |||||
#include <spdlog/fmt/fmt.h> | #include <spdlog/fmt/fmt.h> | ||||
} | } | ||||
}; | }; | ||||
auto kvs = lm_parse_file(p); | |||||
auto kvs = lm::parse_file(p); | |||||
for (auto&& pair : kvs.items()) { | for (auto&& pair : kvs.items()) { | ||||
auto& key = pair.key(); | auto& key = pair.key(); | ||||
auto& value = pair.value(); | auto& value = pair.value(); | ||||
std::optional<toolchain> toolchain::get_builtin(std::string_view s) noexcept { | std::optional<toolchain> toolchain::get_builtin(std::string_view s) noexcept { | ||||
toolchain ret; | toolchain ret; | ||||
using namespace std::string_literals; | |||||
using namespace std::literals; | |||||
if (starts_with(s, "ccache:")) { | |||||
s = s.substr("ccache:"sv.length()); | |||||
ret._c_compile.push_back("ccache"); | |||||
ret._cxx_compile.push_back("ccache"); | |||||
} | |||||
if (starts_with(s, "gcc") || starts_with(s, "clang")) { | if (starts_with(s, "gcc") || starts_with(s, "clang")) { | ||||
ret._inc_template = {"-isystem", "<PATH>"}; | ret._inc_template = {"-isystem", "<PATH>"}; |
namespace fs = std::filesystem; | namespace fs = std::filesystem; | ||||
using path_ref = const fs::path&; | |||||
std::fstream open(const fs::path& filepath, std::ios::openmode mode, std::error_code& ec); | std::fstream open(const fs::path& filepath, std::ios::openmode mode, std::error_code& ec); | ||||
std::string slurp_file(const fs::path& path, std::error_code& ec); | std::string slurp_file(const fs::path& path, std::error_code& ec); | ||||
++::dds::S_failed_checks; \ | ++::dds::S_failed_checks; \ | ||||
std::cerr << "Check failed at " << __FILE__ << ':' << __LINE__ << ": " << #__VA_ARGS__ \ | std::cerr << "Check failed at " << __FILE__ << ':' << __LINE__ << ": " << #__VA_ARGS__ \ | ||||
<< "\n"; \ | << "\n"; \ | ||||
throw requirement_failed(); \ | |||||
throw ::dds::requirement_failed(); \ | |||||
} \ | } \ | ||||
} while (0) | } while (0) | ||||
int main() { \ | int main() { \ | ||||
try { \ | try { \ | ||||
run_tests(); \ | run_tests(); \ | ||||
} catch (const requirement_failed&) { \ | |||||
return S_failed_checks; \ | |||||
} catch (const ::dds::requirement_failed&) { \ | |||||
return ::dds::S_failed_checks; \ | |||||
} catch (const std::exception& e) { \ | } catch (const std::exception& e) { \ | ||||
std::cerr << "An unhandled exception occured: " << e.what() << '\n'; \ | std::cerr << "An unhandled exception occured: " << e.what() << '\n'; \ | ||||
return 2; \ | return 2; \ |
#include "./lm_parse.hpp" | |||||
#include "./parse.hpp" | |||||
#include <dds/util.hpp> | #include <dds/util.hpp> | ||||
using namespace std::literals; | using namespace std::literals; | ||||
using namespace dds; | |||||
using namespace lm; | |||||
namespace { | namespace { | ||||
return sview(iter, new_end); | return sview(iter, new_end); | ||||
} | } | ||||
void parse_line(std::vector<lm_pair>& pairs, const std::string_view whole_line) { | |||||
void parse_line(std::vector<pair>& pairs, const std::string_view whole_line) { | |||||
const auto line = trim(whole_line); | const auto line = trim(whole_line); | ||||
if (line.empty() || line[0] == '#') { | if (line.empty() || line[0] == '#') { | ||||
return; | return; | ||||
} // namespace | } // namespace | ||||
dds::lm_kv_pairs dds::lm_parse_string(std::string_view s) { | |||||
std::vector<lm_pair> pairs; | |||||
pair_list lm::parse_string(std::string_view s) { | |||||
std::vector<pair> pairs; | |||||
auto line_begin = s.begin(); | auto line_begin = s.begin(); | ||||
auto iter = line_begin; | auto iter = line_begin; | ||||
if (line_begin != end) { | if (line_begin != end) { | ||||
parse_line(pairs, sview(line_begin, end)); | parse_line(pairs, sview(line_begin, end)); | ||||
} | } | ||||
return lm_kv_pairs(std::move(pairs)); | |||||
return pair_list(std::move(pairs)); | |||||
} | } | ||||
dds::lm_kv_pairs dds::lm_parse_file(fs::path fpath) { return lm_parse_string(slurp_file(fpath)); } | |||||
lm::pair_list lm::parse_file(fs::path fpath) { return parse_string(dds::slurp_file(fpath)); } | |||||
void dds::lm_write_pairs(fs::path fpath, const std::vector<lm_pair>& pairs) { | |||||
auto fstream = open(fpath, std::ios::out | std::ios::binary); | |||||
void lm::write_pairs(fs::path fpath, const std::vector<pair>& pairs) { | |||||
auto fstream = dds::open(fpath, std::ios::out | std::ios::binary); | |||||
for (auto& pair : pairs) { | for (auto& pair : pairs) { | ||||
fstream << pair.key() << ": " << pair.value() << '\n'; | fstream << pair.key() << ": " << pair.value() << '\n'; | ||||
} | } |
#ifndef DDS_LM_PARSE_HPP_INCLUDED | |||||
#define DDS_LM_PARSE_HPP_INCLUDED | |||||
#pragma once | |||||
#include <cassert> | #include <cassert> | ||||
#include <filesystem> | #include <filesystem> | ||||
#include <utility> | #include <utility> | ||||
#include <vector> | #include <vector> | ||||
namespace dds { | |||||
namespace lm { | |||||
class lm_pair { | |||||
class pair { | |||||
std::string _key; | std::string _key; | ||||
std::string _value; | std::string _value; | ||||
public: | public: | ||||
lm_pair(std::string_view k, std::string_view v) | |||||
pair(std::string_view k, std::string_view v) | |||||
: _key(k) | : _key(k) | ||||
, _value(v) {} | , _value(v) {} | ||||
auto& value() const noexcept { return _value; } | auto& value() const noexcept { return _value; } | ||||
}; | }; | ||||
struct kv_pair_iterator { | |||||
using vec_type = std::vector<lm_pair>; | |||||
class pair_iterator { | |||||
using vec_type = std::vector<pair>; | |||||
using base_iter = vec_type::const_iterator; | using base_iter = vec_type::const_iterator; | ||||
base_iter _iter; | base_iter _iter; | ||||
base_iter _end; | base_iter _end; | ||||
using pointer = vec_type::pointer; | using pointer = vec_type::pointer; | ||||
using reference = vec_type::reference; | using reference = vec_type::reference; | ||||
inline kv_pair_iterator(base_iter, base_iter, std::string_view k); | |||||
inline pair_iterator(base_iter, base_iter, std::string_view k); | |||||
kv_pair_iterator& operator++() & noexcept { | |||||
pair_iterator& operator++() & noexcept { | |||||
assert(_iter != _end); | assert(_iter != _end); | ||||
++_iter; | ++_iter; | ||||
while (_iter != _end && _iter->key() != _key) { | while (_iter != _end && _iter->key() != _key) { | ||||
return *this; | return *this; | ||||
} | } | ||||
const lm_pair* operator->() const noexcept { | |||||
const pair* operator->() const noexcept { | |||||
assert(_iter != _end); | assert(_iter != _end); | ||||
return _iter.operator->(); | return _iter.operator->(); | ||||
} | } | ||||
const lm_pair& operator*() const noexcept { | |||||
const pair& operator*() const noexcept { | |||||
assert(_iter != _end); | assert(_iter != _end); | ||||
return *_iter; | return *_iter; | ||||
} | } | ||||
inline bool operator!=(const kv_pair_iterator& o) const noexcept { return _iter != o._iter; } | |||||
inline bool operator!=(const pair_iterator& o) const noexcept { return _iter != o._iter; } | |||||
auto begin() const noexcept { return *this; } | auto begin() const noexcept { return *this; } | ||||
auto end() const noexcept { return kv_pair_iterator(_end, _end, _key); } | |||||
auto end() const noexcept { return pair_iterator(_end, _end, _key); } | |||||
explicit operator bool() const noexcept { return *this != end(); } | explicit operator bool() const noexcept { return *this != end(); } | ||||
}; | }; | ||||
class lm_kv_pairs { | |||||
std::vector<lm_pair> _kvs; | |||||
class pair_list { | |||||
std::vector<pair> _kvs; | |||||
public: | public: | ||||
explicit lm_kv_pairs(std::vector<lm_pair> kvs) | |||||
explicit pair_list(std::vector<pair> kvs) | |||||
: _kvs(kvs) {} | : _kvs(kvs) {} | ||||
auto& items() const noexcept { return _kvs; } | auto& items() const noexcept { return _kvs; } | ||||
const lm_pair* find(const std::string_view& key) const noexcept { | |||||
const pair* find(const std::string_view& key) const noexcept { | |||||
for (auto&& item : items()) { | for (auto&& item : items()) { | ||||
if (item.key() == key) { | if (item.key() == key) { | ||||
return &item; | return &item; | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
kv_pair_iterator iter(std::string_view key) const noexcept { | |||||
pair_iterator iter(std::string_view key) const noexcept { | |||||
auto iter = items().begin(); | auto iter = items().begin(); | ||||
const auto end = items().end(); | const auto end = items().end(); | ||||
while (iter != end && iter->key() != key) { | while (iter != end && iter->key() != key) { | ||||
++iter; | ++iter; | ||||
} | } | ||||
return kv_pair_iterator{iter, end, key}; | |||||
return pair_iterator{iter, end, key}; | |||||
} | } | ||||
std::vector<lm_pair> all_of(std::string_view key) const noexcept { | |||||
std::vector<pair> all_of(std::string_view key) const noexcept { | |||||
auto iter = this->iter(key); | auto iter = this->iter(key); | ||||
return std::vector<lm_pair>(iter, iter.end()); | |||||
return std::vector<pair>(iter, iter.end()); | |||||
} | } | ||||
auto size() const noexcept { return _kvs.size(); } | auto size() const noexcept { return _kvs.size(); } | ||||
}; | }; | ||||
inline kv_pair_iterator::kv_pair_iterator(base_iter it, base_iter end, std::string_view k) | |||||
inline pair_iterator::pair_iterator(base_iter it, base_iter end, std::string_view k) | |||||
: _iter{it} | : _iter{it} | ||||
, _end{end} | , _end{end} | ||||
, _key{k} {} | , _key{k} {} | ||||
lm_kv_pairs lm_parse_string(std::string_view); | |||||
lm_kv_pairs lm_parse_file(std::filesystem::path); | |||||
void lm_write_pairs(std::filesystem::path, const std::vector<lm_pair>&); | |||||
pair_list parse_string(std::string_view); | |||||
pair_list parse_file(std::filesystem::path); | |||||
void write_pairs(std::filesystem::path, const std::vector<pair>&); | |||||
inline void lm_write_pairs(const std::filesystem::path& fpath, const lm_kv_pairs& pairs) { | |||||
lm_write_pairs(fpath, pairs.items()); | |||||
inline void write_pairs(const std::filesystem::path& fpath, const pair_list& pairs) { | |||||
write_pairs(fpath, pairs.items()); | |||||
} | } | ||||
} // namespace dds | |||||
#endif // DDS_LM_PARSE_HPP_INCLUDED | |||||
} // namespace lm |
#include <dds/lm_parse.hpp> | |||||
#include <dds/util.test.hpp> | #include <dds/util.test.hpp> | ||||
#include <libman/parse.hpp> | |||||
#include <iostream> | #include <iostream> | ||||
using namespace dds; | |||||
using namespace lm; | |||||
void test_simple() { | void test_simple() { | ||||
auto lm_src = ""; | auto lm_src = ""; | ||||
auto kvs = lm_parse_string(lm_src); | |||||
auto kvs = parse_string(lm_src); | |||||
CHECK(kvs.size() == 0); | CHECK(kvs.size() == 0); | ||||
lm_src = "foo: bar"; | lm_src = "foo: bar"; | ||||
kvs = lm_parse_string(lm_src); | |||||
kvs = parse_string(lm_src); | |||||
CHECK(kvs.size() == 1); | CHECK(kvs.size() == 1); | ||||
REQUIRE(kvs.find("foo")); | REQUIRE(kvs.find("foo")); | ||||
CHECK(kvs.find("foo")->value() == "bar"); | CHECK(kvs.find("foo")->value() == "bar"); | ||||
lm_src = "foo:bar: baz"; | lm_src = "foo:bar: baz"; | ||||
kvs = lm_parse_string(lm_src); | |||||
kvs = parse_string(lm_src); | |||||
CHECK(kvs.size() == 1); | CHECK(kvs.size() == 1); | ||||
REQUIRE(kvs.find("foo:bar")); | REQUIRE(kvs.find("foo:bar")); | ||||
CHECK(kvs.find("foo:bar")->value() == "baz"); | CHECK(kvs.find("foo:bar")->value() == "baz"); | ||||
CHECK(lm_parse_string("#comment").size() == 0); | |||||
CHECK(lm_parse_string("\n\n").size() == 0); | |||||
CHECK(lm_parse_string("\n#comment").size() == 0); | |||||
CHECK(lm_parse_string("#comment\n\n").size() == 0); | |||||
CHECK(parse_string("#comment").size() == 0); | |||||
CHECK(parse_string("\n\n").size() == 0); | |||||
CHECK(parse_string("\n#comment").size() == 0); | |||||
CHECK(parse_string("#comment\n\n").size() == 0); | |||||
std::vector<std::string_view> empty_foos = { | std::vector<std::string_view> empty_foos = { | ||||
"Foo:", | "Foo:", | ||||
"Foo :\n", | "Foo :\n", | ||||
}; | }; | ||||
for (auto s : empty_foos) { | for (auto s : empty_foos) { | ||||
kvs = lm_parse_string(s); | |||||
kvs = parse_string(s); | |||||
CHECK(kvs.size() == 1); | CHECK(kvs.size() == 1); | ||||
REQUIRE(kvs.find("Foo")); | REQUIRE(kvs.find("Foo")); | ||||
CHECK(kvs.find("Foo")->value() == ""); | CHECK(kvs.find("Foo")->value() == ""); | ||||
} | } | ||||
kvs = lm_parse_string("foo: # Not a comment"); | |||||
kvs = parse_string("foo: # Not a comment"); | |||||
CHECK(kvs.size() == 1); | CHECK(kvs.size() == 1); | ||||
REQUIRE(kvs.find("foo")); | REQUIRE(kvs.find("foo")); | ||||
CHECK(kvs.find("foo")->value() == "# Not a comment"); | CHECK(kvs.find("foo")->value() == "# Not a comment"); | ||||
} | } | ||||
void test_multi() { | void test_multi() { | ||||
auto kvs = lm_parse_string("Foo: bar\nbaz: qux"); | |||||
auto kvs = parse_string("Foo: bar\nbaz: qux"); | |||||
CHECK(kvs.size() == 2); | CHECK(kvs.size() == 2); | ||||
REQUIRE(kvs.find("Foo")); | REQUIRE(kvs.find("Foo")); | ||||
CHECK(kvs.find("Foo")->value() == "bar"); | CHECK(kvs.find("Foo")->value() == "bar"); | ||||
REQUIRE(kvs.find("baz")); | REQUIRE(kvs.find("baz")); | ||||
CHECK(kvs.find("baz")->value() == "qux"); | CHECK(kvs.find("baz")->value() == "qux"); | ||||
kvs = lm_parse_string("foo: first\nfoo: second\n"); | |||||
kvs = parse_string("foo: first\nfoo: second\n"); | |||||
CHECK(kvs.size() == 2); | CHECK(kvs.size() == 2); | ||||
auto iter = kvs.iter("foo"); | auto iter = kvs.iter("foo"); | ||||
REQUIRE(iter); | REQUIRE(iter); |