File diff suppressed because one or more lines are too long
271
src/Config.cppm
271
src/Config.cppm
@@ -1,271 +0,0 @@
|
||||
module;
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
}
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "dhos_config.h"
|
||||
|
||||
export module LunarWM.Config;
|
||||
|
||||
import std;
|
||||
|
||||
static auto default_configuration_paths()
|
||||
-> std::vector<std::filesystem::path> const
|
||||
{
|
||||
std::vector<std::filesystem::path> paths = {
|
||||
"lunarwm/lunarwm.dcfg",
|
||||
"lunarwm.dcfg",
|
||||
"/etc/lunarwm.dcfg",
|
||||
"/etc/lunarwm/lunarwm.dcfg",
|
||||
};
|
||||
|
||||
if (char const *xdg_dirs
|
||||
= std::getenv("XDG_CONFIG_DIRS")) { // NOLINT(concurrency-mt-unsafe)
|
||||
std::string const dirs { xdg_dirs };
|
||||
std::istringstream ss { dirs };
|
||||
std::string dir;
|
||||
while (std::getline(ss, dir, ':')) {
|
||||
if (!dir.empty()) {
|
||||
paths.push_back(
|
||||
std::filesystem::path(dir) / "lunarwm/lunarwm.dcfg");
|
||||
paths.push_back(std::filesystem::path(dir) / "lunarwm.dcfg");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (char const *home
|
||||
= std::getenv("HOME")) { // NOLINT(concurrency-mt-unsafe)
|
||||
std::filesystem::path const home_path(home);
|
||||
paths.push_back(home_path / ".config/lunarwm/lunarwm.dcfg");
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
static inline auto string_to_modifier(std::string_view str)
|
||||
-> std::optional<wlr_keyboard_modifier>
|
||||
{
|
||||
if (boost::iequals(str, "shift")) {
|
||||
return WLR_MODIFIER_SHIFT;
|
||||
} else if (boost::iequals(str, "ctrl")) {
|
||||
return WLR_MODIFIER_CTRL;
|
||||
} else if (boost::iequals(str, "alt")) {
|
||||
return WLR_MODIFIER_ALT;
|
||||
} else if (boost::iequals(str, "mod2")) {
|
||||
return WLR_MODIFIER_MOD2;
|
||||
} else if (boost::iequals(str, "mod3")) {
|
||||
return WLR_MODIFIER_MOD3;
|
||||
} else if (boost::iequals(str, "logo") || boost::iequals(str, "win")
|
||||
|| boost::iequals(str, "super") || boost::iequals(str, "mod4")) {
|
||||
return WLR_MODIFIER_LOGO;
|
||||
} else if (boost::iequals(str, "mod5")) {
|
||||
return WLR_MODIFIER_MOD5;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
export namespace LunarWM::Config {
|
||||
|
||||
struct Configuration {
|
||||
dhos::Value e;
|
||||
|
||||
struct KeyCombo {
|
||||
uint32_t modifiers {};
|
||||
xkb_keysym_t sym {};
|
||||
|
||||
static auto parse(std::string const &str,
|
||||
std::unordered_map<std::string, uint32_t> const &modifier_alias)
|
||||
-> std::optional<Configuration::KeyCombo>;
|
||||
};
|
||||
struct Keybind {
|
||||
KeyCombo combo;
|
||||
dhos::Value action;
|
||||
};
|
||||
|
||||
struct {
|
||||
struct {
|
||||
std::vector<std::string> xkb_options;
|
||||
} keyboard {};
|
||||
} input {};
|
||||
|
||||
std::unordered_map<std::string, uint32_t> modifier_aliases;
|
||||
std::vector<Keybind> keybindings;
|
||||
|
||||
dhos::Object custom_lib;
|
||||
|
||||
void execute_keybind(Keybind const &keybind)
|
||||
{
|
||||
dhos::eval(keybind.action, &this->custom_lib);
|
||||
}
|
||||
|
||||
void add_to_custom_lib(std::string const &name, dhos::Builtin const &fn)
|
||||
{
|
||||
this->custom_lib.insert_or_assign(name, dhos::Value(fn, e.env));
|
||||
}
|
||||
|
||||
void load() { this->load(default_configuration_paths()); }
|
||||
void load(std::vector<std::filesystem::path> const &paths);
|
||||
};
|
||||
|
||||
auto Configuration::KeyCombo::parse(std::string const &str,
|
||||
std::unordered_map<std::string, uint32_t> const &modifier_alias)
|
||||
-> std::optional<Configuration::KeyCombo>
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
std::string component;
|
||||
std::vector<std::string> components;
|
||||
components.reserve(5);
|
||||
while (std::getline(iss, component, '-')) {
|
||||
boost::algorithm::trim(component);
|
||||
if (component.empty()) {
|
||||
continue;
|
||||
}
|
||||
components.push_back(component);
|
||||
}
|
||||
|
||||
if (components.size() < 2) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
wlr_keyboard_modifier mods {};
|
||||
for (auto const &entry :
|
||||
std::span(components.begin(), components.end() - 1)) {
|
||||
auto mod_opt = string_to_modifier(entry);
|
||||
if (!mod_opt) {
|
||||
if (modifier_alias.contains(entry)) {
|
||||
mod_opt = static_cast<wlr_keyboard_modifier>(
|
||||
modifier_alias.at(entry));
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
mods = static_cast<wlr_keyboard_modifier>(
|
||||
static_cast<unsigned>(mods) | static_cast<unsigned>(*mod_opt));
|
||||
}
|
||||
|
||||
auto const &key_name = components.back();
|
||||
xkb_keysym_t const sym = xkb_keysym_from_name(key_name.c_str(),
|
||||
static_cast<enum xkb_keysym_flags>(XKB_KEYSYM_CASE_INSENSITIVE));
|
||||
if (sym == XKB_KEY_NoSymbol) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Configuration::KeyCombo const combo {
|
||||
.modifiers = mods,
|
||||
.sym = sym,
|
||||
};
|
||||
return combo;
|
||||
}
|
||||
|
||||
void Configuration::load(std::vector<std::filesystem::path> const &paths)
|
||||
{
|
||||
for (auto const &path : paths) {
|
||||
try {
|
||||
e = dhos::eval(dhos::parse_config(path), &this->custom_lib);
|
||||
if (!e.is_obj()) {
|
||||
throw std::runtime_error("Top level is not an object!");
|
||||
}
|
||||
|
||||
static dhos::Object base = dhos::make_default_lib();
|
||||
auto merged = dhos::merge_lib(base, &this->custom_lib);
|
||||
dhos::get_env_tbl(&*e.env)["lib"] = dhos::Value(merged, e.env);
|
||||
|
||||
if (e["input"].is_obj()) {
|
||||
auto const &input = e["input"];
|
||||
if (input["keyboard"].is_obj()) {
|
||||
auto const &keyboard = input["keyboard"];
|
||||
if (keyboard["xkb_options"].is_arr()) {
|
||||
auto const &arr = keyboard["xkb_options"].arr();
|
||||
this->input.keyboard.xkb_options.clear();
|
||||
for (auto const &value : arr) {
|
||||
if (value.is_str()) {
|
||||
this->input.keyboard.xkb_options.push_back(
|
||||
value.str());
|
||||
} else {
|
||||
// FIXME: Send warning
|
||||
std::println("Invalid xkb_options type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e["modifier_aliases"].is_obj()) {
|
||||
auto const &modifier_aliases = e["modifier_aliases"];
|
||||
this->modifier_aliases.clear();
|
||||
|
||||
for (auto const &[k, v] : modifier_aliases.obj()) {
|
||||
if (!v.is_str()) {
|
||||
// FIXME: Send warning
|
||||
std::println("Invalid modifier aliases value");
|
||||
continue;
|
||||
} else {
|
||||
auto const to_parse = v.str() + "-a";
|
||||
std::println(
|
||||
"Sending alias value to parse: {}", to_parse);
|
||||
auto const kc_opt = KeyCombo::parse(to_parse, {});
|
||||
if (kc_opt) {
|
||||
auto const mod_opt = kc_opt->modifiers;
|
||||
this->modifier_aliases[k] = mod_opt;
|
||||
} else {
|
||||
// FIXME: Send warning
|
||||
std::println(
|
||||
"Invalid modifier aliases value format");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e["keybindings"].is_arr()) {
|
||||
auto const &keybindings = e["keybindings"].arr();
|
||||
this->keybindings.clear();
|
||||
|
||||
for (auto const &v : keybindings) {
|
||||
if (v.is_obj()) {
|
||||
auto const &o = v.obj();
|
||||
if (!o.contains("bind") || !o.contains("action")
|
||||
|| !o.at("bind").is_str()
|
||||
|| !o.at("action").is_call()) {
|
||||
// FIXME: Send warning
|
||||
std::println("Invalid keybinding object format");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const combo_opt = KeyCombo::parse(
|
||||
o.at("bind").str(), this->modifier_aliases);
|
||||
if (!combo_opt) {
|
||||
// FIXME: Send warning
|
||||
std::println("Invalid keybinding combo");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const &combo = *combo_opt;
|
||||
|
||||
this->keybindings.push_back({
|
||||
.combo = combo,
|
||||
.action = o.at("action"),
|
||||
});
|
||||
} else {
|
||||
// FIXME: Send warning
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (std::filesystem::filesystem_error const &e) {
|
||||
(void)e;
|
||||
} catch (std::exception &e) {
|
||||
(void)e;
|
||||
std::println("Exception for config file: {}", e.what());
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Unable to find a valid configuration file!");
|
||||
}
|
||||
|
||||
} // LunarWM::Config
|
||||
1572
src/LunarWM.c
Normal file
1572
src/LunarWM.c
Normal file
File diff suppressed because it is too large
Load Diff
1818
src/LunarWM.cppm
1818
src/LunarWM.cppm
File diff suppressed because it is too large
Load Diff
173
src/LunarWM.h
Normal file
173
src/LunarWM.h
Normal file
@@ -0,0 +1,173 @@
|
||||
#ifndef LUNAR_WM_H
|
||||
#define LUNAR_WM_H
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <GLES3/gl3.h>
|
||||
#include <GLES3/gl31.h>
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-egl.h>
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/backend/wayland.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/egl.h>
|
||||
#include <wlr/render/gles2.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/types/wlr_pointer.h>
|
||||
#include <wlr/types/wlr_subcompositor.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include <raylib.h>
|
||||
#include <raymath.h>
|
||||
#include <rlgl.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct LunarWM;
|
||||
|
||||
typedef struct {
|
||||
struct LunarWM *server;
|
||||
|
||||
struct wl_list link;
|
||||
struct wlr_keyboard *wlr_keyboard;
|
||||
|
||||
struct wl_listener modifiers;
|
||||
struct wl_listener key;
|
||||
struct wl_listener destroy;
|
||||
} LunarWM_Keyboard;
|
||||
|
||||
typedef struct {
|
||||
struct LunarWM *server;
|
||||
|
||||
struct wl_listener commit;
|
||||
struct wl_listener destroy;
|
||||
|
||||
struct wlr_xdg_toplevel *xdg_toplevel;
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_texture *texture;
|
||||
|
||||
struct wlr_buffer *locked_buffer;
|
||||
struct wlr_gles2_texture_attribs attribs;
|
||||
struct wlr_gles2_texture *gles_texture;
|
||||
Texture2D rl_texture;
|
||||
} LunarWM_Toplevel;
|
||||
|
||||
bool LunarWM_Toplevel_init(
|
||||
LunarWM_Toplevel *tl, struct LunarWM *wm, struct wlr_xdg_toplevel *xdg);
|
||||
bool LunarWM_Toplevel_destroy(LunarWM_Toplevel *this);
|
||||
|
||||
bool LunarWM_Toplevel_update(LunarWM_Toplevel *this);
|
||||
|
||||
typedef struct {
|
||||
XrSwapchain swapchain;
|
||||
int64_t swapchain_format;
|
||||
GLuint *v_image_views;
|
||||
} LunarWM_SwapchainInfo;
|
||||
|
||||
typedef struct {
|
||||
XrSwapchain handle;
|
||||
XrSwapchainImageOpenGLESKHR *a_imgs;
|
||||
uint32_t a_imgs_count;
|
||||
} LunarWM_SwapchainImagesEntry;
|
||||
|
||||
typedef struct {
|
||||
XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT];
|
||||
XrHandTrackerEXT hand_tracker;
|
||||
} LunarWM_Hand;
|
||||
|
||||
typedef struct {
|
||||
XrTime predicted_display_time;
|
||||
XrCompositionLayerProjection layer_projection;
|
||||
XrCompositionLayerBaseHeader *layers[10];
|
||||
uint32_t layers_count;
|
||||
XrCompositionLayerProjectionView
|
||||
layer_projection_views[10]; // Hopefully we dont have more than 10.
|
||||
uint32_t layer_projection_views_count;
|
||||
} LunarWM_RenderLayerInfo;
|
||||
|
||||
typedef struct LunarWM {
|
||||
struct {
|
||||
struct wl_display *display;
|
||||
struct wl_event_loop *event_loop;
|
||||
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_session *session;
|
||||
|
||||
struct wlr_egl *egl;
|
||||
EGLDisplay egl_display;
|
||||
EGLContext egl_context;
|
||||
EGLConfig egl_config;
|
||||
|
||||
struct wlr_allocator *allocator;
|
||||
struct wlr_compositor *compositor;
|
||||
struct wlr_subcompositor *subcompositor;
|
||||
struct wlr_data_device_manager *data_device_manager;
|
||||
|
||||
struct wlr_seat *seat;
|
||||
struct wl_list keyboards;
|
||||
struct wl_listener new_input_listener;
|
||||
|
||||
struct wlr_xdg_shell *xdg_shell;
|
||||
struct wl_listener new_xdg_toplevel_listener;
|
||||
struct wl_listener new_xdg_popup_listener;
|
||||
|
||||
struct wlr_cursor *cursor;
|
||||
|
||||
LunarWM_Toplevel **v_toplevels;
|
||||
} wayland;
|
||||
|
||||
struct {
|
||||
XrInstance instance;
|
||||
XrSystemId system_id;
|
||||
XrSession session;
|
||||
XrSessionState session_state;
|
||||
struct {
|
||||
LunarWM_SwapchainInfo *v_color;
|
||||
LunarWM_SwapchainInfo *v_depth;
|
||||
} swapchains;
|
||||
LunarWM_SwapchainImagesEntry
|
||||
swapchain_images[2]; // 0 is color, 1 is depth
|
||||
XrViewConfigurationView *a_view_configuration_views;
|
||||
uint32_t view_configuration_views_count;
|
||||
XrEnvironmentBlendMode environment_blend_mode;
|
||||
XrSpace local_space, view_space;
|
||||
LunarWM_Hand hands[2];
|
||||
XrSystemHandTrackingPropertiesEXT hand_tracking_system_properties;
|
||||
|
||||
PFN_xrCreateHandTrackerEXT CreateHandTrackerEXT;
|
||||
PFN_xrDestroyHandTrackerEXT DestroyHandTrackerEXT;
|
||||
PFN_xrLocateHandJointsEXT LocateHandJointsEXT;
|
||||
|
||||
bool session_running;
|
||||
} xr;
|
||||
|
||||
struct {
|
||||
GLuint fbo;
|
||||
RenderTexture2D tmp_rt;
|
||||
Camera3D camera;
|
||||
} renderer;
|
||||
|
||||
bool initialized;
|
||||
bool running;
|
||||
} LunarWM;
|
||||
|
||||
bool LunarWM_init(LunarWM *wm);
|
||||
void LunarWM_destroy(LunarWM *this);
|
||||
|
||||
void LunarWM_terminate(LunarWM *this);
|
||||
void LunarWM_run(LunarWM *this);
|
||||
|
||||
extern LunarWM g_wm;
|
||||
|
||||
#endif // LUNAR_WM_H
|
||||
224
src/Math.cppm
224
src/Math.cppm
@@ -1,224 +0,0 @@
|
||||
export module LunarWM.Math;
|
||||
|
||||
import std;
|
||||
|
||||
export namespace LunarWM::Math {
|
||||
|
||||
template<typename T = float>
|
||||
requires std::is_arithmetic_v<T> struct Vec2 {
|
||||
template<typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
auto operator+(Vec2<U> const &other) -> Vec2<U>
|
||||
{
|
||||
return { x + other.x, y + other.y };
|
||||
}
|
||||
template<typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
auto operator-(Vec2<U> const &other) -> Vec2<U>
|
||||
{
|
||||
return { x - other.x, y - other.y };
|
||||
}
|
||||
template<typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
auto operator*(Vec2<U> const &other) -> Vec2<U>
|
||||
{
|
||||
return { x * other.x, y * other.x };
|
||||
}
|
||||
template<typename U = T>
|
||||
requires std::is_arithmetic_v<U> auto operator*(T scalar) -> Vec2<U>
|
||||
{
|
||||
return { x * scalar, y * scalar };
|
||||
}
|
||||
template<typename U = T>
|
||||
requires std::is_arithmetic_v<U> auto operator/(T scalar) -> Vec2<U>
|
||||
{
|
||||
return { x / scalar, y / scalar };
|
||||
}
|
||||
template<typename U = T>
|
||||
requires std::is_arithmetic_v<U> auto operator-() -> Vec2
|
||||
{
|
||||
return { -x, -y };
|
||||
}
|
||||
auto length() const -> T { return std::sqrt(x * x + y * y); }
|
||||
auto lengthSquared() const -> T { return x * x + y * y; }
|
||||
auto normalized() const -> Vec2<T>
|
||||
{
|
||||
T len = length();
|
||||
if (len == T(0)) {
|
||||
return { T(0), T(0) };
|
||||
}
|
||||
return *this / len;
|
||||
}
|
||||
|
||||
T x, y;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
requires std::is_arithmetic_v<T>
|
||||
auto operator*(T scalar, Vec2<T> const &v) -> Vec2<T>
|
||||
{
|
||||
return { v.x * scalar, v.y * scalar };
|
||||
}
|
||||
|
||||
template<typename T = float>
|
||||
requires std::is_arithmetic_v<T> struct Rect {
|
||||
Rect(Vec2<T> pos, Vec2<T> size)
|
||||
: pos(pos)
|
||||
, size(size)
|
||||
{
|
||||
}
|
||||
Rect(T x, T y, T w, T h)
|
||||
: pos({ x, y })
|
||||
, size({ w, h })
|
||||
{
|
||||
}
|
||||
|
||||
auto x() -> T & { return pos.x; }
|
||||
auto y() -> T & { return pos.y; }
|
||||
auto w() -> T & { return size.x; }
|
||||
auto h() -> T & { return size.y; }
|
||||
|
||||
auto x() const -> T { return pos.x; }
|
||||
auto y() const -> T { return pos.y; }
|
||||
auto w() const -> T { return size.x; }
|
||||
auto h() const -> T { return size.y; }
|
||||
|
||||
auto left() const -> T { return x(); }
|
||||
auto right() const -> T { return x() + w(); }
|
||||
auto top() const -> T { return y(); }
|
||||
auto bottom() const -> T { return y() + h(); }
|
||||
|
||||
auto left() -> T & { return x(); }
|
||||
auto top() -> T & { return y(); }
|
||||
|
||||
Vec2<T> pos, size;
|
||||
};
|
||||
|
||||
template<typename T = float>
|
||||
requires std::is_arithmetic_v<T> struct Box {
|
||||
template<typename U = int>
|
||||
requires std::is_arithmetic_v<U> auto operator[](U const index) -> Vec2<T> &
|
||||
{
|
||||
if (index < 0 || index > 1) {
|
||||
throw std::out_of_range("A box only has two points");
|
||||
}
|
||||
return m_data[index];
|
||||
}
|
||||
auto first() -> Vec2<T> & { return m_data[0]; }
|
||||
auto second() -> Vec2<T> & { return m_data[1]; }
|
||||
auto x0() -> T & { return m_data[0].x; }
|
||||
auto y0() -> T & { return m_data[0].y; }
|
||||
auto x1() -> T & { return m_data[1].x; }
|
||||
auto y1() -> T & { return m_data[1].y; }
|
||||
auto left() -> T &
|
||||
{
|
||||
if (x0() < x1()) {
|
||||
return x0();
|
||||
}
|
||||
return x1();
|
||||
}
|
||||
auto right() -> T &
|
||||
{
|
||||
if (x0() > x1()) {
|
||||
return x0();
|
||||
}
|
||||
return x1();
|
||||
}
|
||||
auto top() -> T &
|
||||
{
|
||||
if (y0() < y1()) {
|
||||
return y0();
|
||||
}
|
||||
return y1();
|
||||
}
|
||||
auto bottom() -> T &
|
||||
{
|
||||
if (y0() > y1()) {
|
||||
return y0();
|
||||
}
|
||||
return y1();
|
||||
}
|
||||
|
||||
Box() = default;
|
||||
explicit Box(Rect<T> rect)
|
||||
{
|
||||
this->m_data[0] = rect.pos;
|
||||
this->m_data[1] = rect.pos + rect.size;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<Vec2<T>, 2> m_data = {};
|
||||
};
|
||||
|
||||
template<typename T = int>
|
||||
requires std::is_arithmetic_v<T>
|
||||
auto subtract_rect(Math::Rect<T> const &src, Math::Rect<T> const &clip)
|
||||
-> std::vector<Math::Rect<T>>
|
||||
{
|
||||
std::vector<Math::Rect<T>> result;
|
||||
|
||||
auto sx = src.x();
|
||||
auto sy = src.y();
|
||||
auto sw = src.w();
|
||||
auto sh = src.h();
|
||||
|
||||
auto cx = clip.x();
|
||||
auto cy = clip.y();
|
||||
auto cw = clip.w();
|
||||
auto ch = clip.h();
|
||||
|
||||
T s_right = sx + sw;
|
||||
T s_bottom = sy + sh;
|
||||
|
||||
T c_right = cx + cw;
|
||||
T c_bottom = cy + ch;
|
||||
|
||||
// No overlap → keep src
|
||||
if (c_right <= sx || cx >= s_right || c_bottom <= sy || cy >= s_bottom) {
|
||||
result.push_back(src);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Top piece
|
||||
if (cy > sy) {
|
||||
result.emplace_back(sx, sy, sw, cy - sy);
|
||||
}
|
||||
|
||||
// Bottom piece
|
||||
if (c_bottom < s_bottom) {
|
||||
result.emplace_back(sx, c_bottom, sw, s_bottom - c_bottom);
|
||||
}
|
||||
|
||||
// Middle pieces left and right of clip
|
||||
T middle_top = std::max(sy, cy);
|
||||
T middle_bottom = std::min(s_bottom, c_bottom);
|
||||
T middle_height = middle_bottom - middle_top;
|
||||
|
||||
if (middle_height > 0) {
|
||||
// Left piece
|
||||
if (cx > sx) {
|
||||
result.emplace_back(sx, middle_top, cx - sx, middle_height);
|
||||
}
|
||||
|
||||
// Right piece
|
||||
if (c_right < s_right) {
|
||||
result.emplace_back(
|
||||
c_right, middle_top, s_right - c_right, middle_height);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T = float>
|
||||
requires std::is_arithmetic_v<T> struct Viewport {
|
||||
Rect<T> rect;
|
||||
Vec2<T> depth_limits;
|
||||
};
|
||||
|
||||
template<typename T> constexpr auto deg2rad(T degrees) -> T
|
||||
{
|
||||
return degrees * (std::numbers::pi / 180.0);
|
||||
}
|
||||
|
||||
} // namespace LunarWM::Math
|
||||
676
src/Util.cppm
676
src/Util.cppm
@@ -1,676 +0,0 @@
|
||||
module;
|
||||
|
||||
// NOLINTBEGIN
|
||||
#include <openxr/openxr.h>
|
||||
// NOLINTEND
|
||||
|
||||
export module LunarWM.Util;
|
||||
|
||||
import std;
|
||||
|
||||
namespace std {
|
||||
template<> struct formatter<XrResult, char> {
|
||||
template<class ParseContext> constexpr auto parse(ParseContext &ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
static constexpr auto to_string(XrResult r) -> std::string_view
|
||||
{
|
||||
switch (r) {
|
||||
case XR_FRAME_DISCARDED:
|
||||
return "XR_FRAME_DISCARDED";
|
||||
case XR_ERROR_VALIDATION_FAILURE:
|
||||
return "XR_ERROR_VALIDATION_FAILURE: The function usage was "
|
||||
"invalid in "
|
||||
"some way.";
|
||||
case XR_ERROR_RUNTIME_FAILURE:
|
||||
return "XR_ERROR_RUNTIME_FAILURE: The runtime failed to handle the "
|
||||
"function in an unexpected way that is not covered by "
|
||||
"another "
|
||||
"error result.";
|
||||
case XR_ERROR_OUT_OF_MEMORY:
|
||||
return "XR_ERROR_OUT_OF_MEMORY: A memory allocation has failed.";
|
||||
case XR_ERROR_API_VERSION_UNSUPPORTED:
|
||||
return "XR_ERROR_API_VERSION_UNSUPPORTED: The runtime does not "
|
||||
"support "
|
||||
"the requested API version.";
|
||||
case XR_ERROR_INITIALIZATION_FAILED:
|
||||
return "XR_ERROR_INITIALIZATION_FAILED: Initialization of object "
|
||||
"could "
|
||||
"not be completed.";
|
||||
case XR_ERROR_FUNCTION_UNSUPPORTED:
|
||||
return "XR_ERROR_FUNCTION_UNSUPPORTED: The requested function was "
|
||||
"not "
|
||||
"found or is otherwise unsupported.";
|
||||
case XR_ERROR_FEATURE_UNSUPPORTED:
|
||||
return "XR_ERROR_FEATURE_UNSUPPORTED: The requested feature is not "
|
||||
"supported.";
|
||||
case XR_ERROR_EXTENSION_NOT_PRESENT:
|
||||
return "XR_ERROR_EXTENSION_NOT_PRESENT: A requested extension is "
|
||||
"not "
|
||||
"supported.";
|
||||
case XR_ERROR_LIMIT_REACHED:
|
||||
return "XR_ERROR_LIMIT_REACHED: The runtime supports no more of "
|
||||
"the "
|
||||
"requested resource.";
|
||||
case XR_ERROR_SIZE_INSUFFICIENT:
|
||||
return "XR_ERROR_SIZE_INSUFFICIENT: The supplied size was smaller "
|
||||
"than "
|
||||
"required.";
|
||||
case XR_ERROR_HANDLE_INVALID:
|
||||
return "XR_ERROR_HANDLE_INVALID: A supplied object handle was "
|
||||
"invalid.";
|
||||
case XR_ERROR_INSTANCE_LOST:
|
||||
return "XR_ERROR_INSTANCE_LOST: The XrInstance was lost or could "
|
||||
"not be "
|
||||
"found. It will need to be destroyed and optionally "
|
||||
"recreated.";
|
||||
case XR_ERROR_SESSION_RUNNING:
|
||||
return "XR_ERROR_SESSION_RUNNING: The session is already running.";
|
||||
case XR_ERROR_SESSION_NOT_RUNNING:
|
||||
return "XR_ERROR_SESSION_NOT_RUNNING: The session is not yet "
|
||||
"running.";
|
||||
case XR_ERROR_SESSION_LOST:
|
||||
return "XR_ERROR_SESSION_LOST: The XrSession was lost. It will "
|
||||
"need to "
|
||||
"be destroyed and optionally recreated.";
|
||||
case XR_ERROR_SYSTEM_INVALID:
|
||||
return "XR_ERROR_SYSTEM_INVALID: The provided XrSystemId was "
|
||||
"invalid.";
|
||||
case XR_ERROR_PATH_INVALID:
|
||||
return "XR_ERROR_PATH_INVALID: The provided XrPath was not valid.";
|
||||
case XR_ERROR_PATH_COUNT_EXCEEDED:
|
||||
return "XR_ERROR_PATH_COUNT_EXCEEDED: The maximum number of "
|
||||
"supported "
|
||||
"semantic paths has been reached.";
|
||||
case XR_ERROR_PATH_FORMAT_INVALID:
|
||||
return "XR_ERROR_PATH_FORMAT_INVALID: The semantic path character "
|
||||
"format "
|
||||
"is invalid.";
|
||||
case XR_ERROR_PATH_UNSUPPORTED:
|
||||
return "XR_ERROR_PATH_UNSUPPORTED: The semantic path is "
|
||||
"unsupported.";
|
||||
case XR_ERROR_LAYER_INVALID:
|
||||
return "XR_ERROR_LAYER_INVALID: The layer was NULL or otherwise "
|
||||
"invalid.";
|
||||
case XR_ERROR_LAYER_LIMIT_EXCEEDED:
|
||||
return "XR_ERROR_LAYER_LIMIT_EXCEEDED: The number of specified "
|
||||
"layers is "
|
||||
"greater than the supported number.";
|
||||
case XR_ERROR_SWAPCHAIN_RECT_INVALID:
|
||||
return "XR_ERROR_SWAPCHAIN_RECT_INVALID: The image rect was "
|
||||
"negatively "
|
||||
"sized or otherwise invalid.";
|
||||
case XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED:
|
||||
return "XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED: The image format is "
|
||||
"not "
|
||||
"supported by the runtime or platform.";
|
||||
case XR_ERROR_ACTION_TYPE_MISMATCH:
|
||||
return "XR_ERROR_ACTION_TYPE_MISMATCH: The API used to retrieve an "
|
||||
"action’s state does not match the action’s type.";
|
||||
case XR_ERROR_SESSION_NOT_READY:
|
||||
return "XR_ERROR_SESSION_NOT_READY: The session is not in the "
|
||||
"ready "
|
||||
"state.";
|
||||
case XR_ERROR_SESSION_NOT_STOPPING:
|
||||
return "XR_ERROR_SESSION_NOT_STOPPING: The session is not in the "
|
||||
"stopping state.";
|
||||
case XR_ERROR_TIME_INVALID:
|
||||
return "XR_ERROR_TIME_INVALID: The provided XrTime was zero, "
|
||||
"negative, "
|
||||
"or out of range.";
|
||||
case XR_ERROR_REFERENCE_SPACE_UNSUPPORTED:
|
||||
return "XR_ERROR_REFERENCE_SPACE_UNSUPPORTED: The specified "
|
||||
"reference "
|
||||
"space is not supported by the runtime or system.";
|
||||
case XR_ERROR_FILE_ACCESS_ERROR:
|
||||
return "XR_ERROR_FILE_ACCESS_ERROR: The file could not be "
|
||||
"accessed.";
|
||||
case XR_ERROR_FILE_CONTENTS_INVALID:
|
||||
return "XR_ERROR_FILE_CONTENTS_INVALID: The file’s contents were "
|
||||
"invalid.";
|
||||
case XR_ERROR_FORM_FACTOR_UNSUPPORTED:
|
||||
return "XR_ERROR_FORM_FACTOR_UNSUPPORTED: The specified form "
|
||||
"factor is "
|
||||
"not supported by the current runtime or platform.";
|
||||
case XR_ERROR_FORM_FACTOR_UNAVAILABLE:
|
||||
return "XR_ERROR_FORM_FACTOR_UNAVAILABLE: The specified form "
|
||||
"factor is "
|
||||
"supported, but the device is currently not available, e.g. "
|
||||
"not "
|
||||
"plugged in or powered off.";
|
||||
case XR_ERROR_API_LAYER_NOT_PRESENT:
|
||||
return "XR_ERROR_API_LAYER_NOT_PRESENT: A requested API layer is "
|
||||
"not "
|
||||
"present or could not be loaded.";
|
||||
case XR_ERROR_CALL_ORDER_INVALID:
|
||||
return "XR_ERROR_CALL_ORDER_INVALID: The call was made without "
|
||||
"having "
|
||||
"made a previously required call.";
|
||||
case XR_ERROR_GRAPHICS_DEVICE_INVALID:
|
||||
return "XR_ERROR_GRAPHICS_DEVICE_INVALID: The given graphics "
|
||||
"device is "
|
||||
"not in a valid state. The graphics device could be lost or "
|
||||
"initialized without meeting graphics requirements.";
|
||||
case XR_ERROR_POSE_INVALID:
|
||||
return "XR_ERROR_POSE_INVALID: The supplied pose was invalid with "
|
||||
"respect to the requirements.";
|
||||
case XR_ERROR_INDEX_OUT_OF_RANGE:
|
||||
return "XR_ERROR_INDEX_OUT_OF_RANGE: The supplied index was "
|
||||
"outside the "
|
||||
"range of valid indices.";
|
||||
case XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED:
|
||||
return "XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED: The "
|
||||
"specified view "
|
||||
"configuration type is not supported by the runtime or "
|
||||
"platform.";
|
||||
case XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED:
|
||||
return "XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED: The specified "
|
||||
"environment blend mode is not supported by the runtime or "
|
||||
"platform.";
|
||||
case XR_ERROR_NAME_DUPLICATED:
|
||||
return "XR_ERROR_NAME_DUPLICATED: The name provided was a "
|
||||
"duplicate of "
|
||||
"an already-existing resource.";
|
||||
case XR_ERROR_NAME_INVALID:
|
||||
return "XR_ERROR_NAME_INVALID: The name provided was invalid.";
|
||||
case XR_ERROR_ACTIONSET_NOT_ATTACHED:
|
||||
return "XR_ERROR_ACTIONSET_NOT_ATTACHED: A referenced action set "
|
||||
"is not "
|
||||
"attached to the session.";
|
||||
case XR_ERROR_ACTIONSETS_ALREADY_ATTACHED:
|
||||
return "XR_ERROR_ACTIONSETS_ALREADY_ATTACHED: The session already "
|
||||
"has "
|
||||
"attached action sets.";
|
||||
case XR_ERROR_LOCALIZED_NAME_DUPLICATED:
|
||||
return "XR_ERROR_LOCALIZED_NAME_DUPLICATED: The localized name "
|
||||
"provided "
|
||||
"was a duplicate of an already-existing resource.";
|
||||
case XR_ERROR_LOCALIZED_NAME_INVALID:
|
||||
return "XR_ERROR_LOCALIZED_NAME_INVALID: The localized name "
|
||||
"provided was "
|
||||
"invalid.";
|
||||
case XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING:
|
||||
return "XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING: The "
|
||||
"xrGetGraphicsRequirements* call was not made before "
|
||||
"calling "
|
||||
"xrCreateSession.";
|
||||
case XR_ERROR_RUNTIME_UNAVAILABLE:
|
||||
return "XR_ERROR_RUNTIME_UNAVAILABLE: The loader was unable to "
|
||||
"find or "
|
||||
"load a runtime.";
|
||||
case XR_ERROR_EXTENSION_DEPENDENCY_NOT_ENABLED:
|
||||
return "XR_ERROR_EXTENSION_DEPENDENCY_NOT_ENABLED: One or more of "
|
||||
"the "
|
||||
"extensions being enabled has dependency on extensions that "
|
||||
"are "
|
||||
"not enabled.";
|
||||
case XR_ERROR_PERMISSION_INSUFFICIENT:
|
||||
return "XR_ERROR_PERMISSION_INSUFFICIENT: Insufficient "
|
||||
"permissions. This "
|
||||
"error is included for use by vendor extensions. The "
|
||||
"precise "
|
||||
"definition of XR_ERROR_PERMISSION_INSUFFICIENT and actions "
|
||||
"possible by the developer or user to resolve it can vary "
|
||||
"by "
|
||||
"platform, extension or function. The developer should "
|
||||
"refer to "
|
||||
"the documentation of the function that returned the error "
|
||||
"code "
|
||||
"and extension it was defined.";
|
||||
case XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR:
|
||||
return "XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR: "
|
||||
"xrSetAndroidApplicationThreadKHR failed as thread id is "
|
||||
"invalid. "
|
||||
"(Added by the XR_KHR_android_thread_settings extension)";
|
||||
case XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR:
|
||||
return "XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR: "
|
||||
"xrSetAndroidApplicationThreadKHR failed setting the thread "
|
||||
"attributes/priority. (Added by the "
|
||||
"XR_KHR_android_thread_settings extension)";
|
||||
case XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT:
|
||||
return "XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT: Spatial anchor "
|
||||
"could "
|
||||
"not be created at that location. (Added by the "
|
||||
"XR_MSFT_spatial_anchor extension)";
|
||||
case XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT:
|
||||
return "XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_"
|
||||
"MSFT: The "
|
||||
"secondary view configuration was not enabled when creating "
|
||||
"the "
|
||||
"session. (Added by the "
|
||||
"XR_MSFT_secondary_view_configuration "
|
||||
"extension)";
|
||||
case XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT:
|
||||
return "XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT: The controller "
|
||||
"model "
|
||||
"key is invalid. (Added by the XR_MSFT_controller_model "
|
||||
"extension)";
|
||||
case XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT:
|
||||
return "XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT: The "
|
||||
"reprojection "
|
||||
"mode is not supported. (Added by the "
|
||||
"XR_MSFT_composition_layer_reprojection extension)";
|
||||
case XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT:
|
||||
return "XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT: Compute new "
|
||||
"scene "
|
||||
"not completed. (Added by the XR_MSFT_scene_understanding "
|
||||
"extension)";
|
||||
case XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT:
|
||||
return "XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT: Scene component "
|
||||
"id "
|
||||
"invalid. (Added by the XR_MSFT_scene_understanding "
|
||||
"extension)";
|
||||
case XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT:
|
||||
return "XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT: Scene "
|
||||
"component "
|
||||
"type mismatch. (Added by the XR_MSFT_scene_understanding "
|
||||
"extension)";
|
||||
case XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT:
|
||||
return "XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT: Scene mesh "
|
||||
"buffer id "
|
||||
"invalid. (Added by the XR_MSFT_scene_understanding "
|
||||
"extension)";
|
||||
case XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT:
|
||||
return "XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT: Scene "
|
||||
"compute "
|
||||
"feature incompatible. (Added by the "
|
||||
"XR_MSFT_scene_understanding "
|
||||
"extension)";
|
||||
case XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT:
|
||||
return "XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT: Scene "
|
||||
"compute "
|
||||
"consistency mismatch. (Added by the "
|
||||
"XR_MSFT_scene_understanding "
|
||||
"extension)";
|
||||
case XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB:
|
||||
return "XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB: The display "
|
||||
"refresh rate is not supported by the platform. (Added by "
|
||||
"the "
|
||||
"XR_FB_display_refresh_rate extension)";
|
||||
case XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB:
|
||||
return "XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB: The color space is "
|
||||
"not "
|
||||
"supported by the runtime. (Added by the XR_FB_color_space "
|
||||
"extension)";
|
||||
case XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB:
|
||||
return "XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB: The component "
|
||||
"type is "
|
||||
"not supported for this space. (Added by the "
|
||||
"XR_FB_spatial_entity "
|
||||
"extension)";
|
||||
case XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB:
|
||||
return "XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB: The required "
|
||||
"component "
|
||||
"is not enabled for this space. (Added by the "
|
||||
"XR_FB_spatial_entity extension)";
|
||||
case XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB:
|
||||
return "XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB: A request to "
|
||||
"set the "
|
||||
"component’s status is currently pending. (Added by the "
|
||||
"XR_FB_spatial_entity extension)";
|
||||
case XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB:
|
||||
return "XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB: The "
|
||||
"component is "
|
||||
"already set to the requested value. (Added by the "
|
||||
"XR_FB_spatial_entity extension)";
|
||||
case XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB:
|
||||
return "XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB: The object state "
|
||||
"is "
|
||||
"unexpected for the issued command. (Added by the "
|
||||
"XR_FB_passthrough extension)";
|
||||
case XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB:
|
||||
return "XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB: Trying to "
|
||||
"create an MR feature when one was already created and only "
|
||||
"one "
|
||||
"instance is allowed. (Added by the XR_FB_passthrough "
|
||||
"extension)";
|
||||
case XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB:
|
||||
return "XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB: Requested "
|
||||
"functionality requires a feature to be created first. "
|
||||
"(Added by "
|
||||
"the XR_FB_passthrough extension)";
|
||||
case XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB:
|
||||
return "XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB: Requested "
|
||||
"functionality "
|
||||
"is not permitted - application is not allowed to perform "
|
||||
"the "
|
||||
"requested operation. (Added by the XR_FB_passthrough "
|
||||
"extension)";
|
||||
case XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB:
|
||||
return "XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB: There were "
|
||||
"insufficient resources available to perform an operation. "
|
||||
"(Added "
|
||||
"by the XR_FB_passthrough extension)";
|
||||
case XR_ERROR_UNKNOWN_PASSTHROUGH_FB:
|
||||
return "XR_ERROR_UNKNOWN_PASSTHROUGH_FB: Unknown Passthrough error "
|
||||
"(no "
|
||||
"further details provided). (Added by the XR_FB_passthrough "
|
||||
"extension)";
|
||||
case XR_ERROR_RENDER_MODEL_KEY_INVALID_FB:
|
||||
return "XR_ERROR_RENDER_MODEL_KEY_INVALID_FB: The model key is "
|
||||
"invalid. "
|
||||
"(Added by the XR_FB_render_model extension)";
|
||||
case XR_ERROR_MARKER_NOT_TRACKED_VARJO:
|
||||
return "XR_ERROR_MARKER_NOT_TRACKED_VARJO: Marker tracking is "
|
||||
"disabled "
|
||||
"or the specified marker is not currently tracked. (Added "
|
||||
"by the "
|
||||
"XR_VARJO_marker_tracking extension)";
|
||||
case XR_ERROR_MARKER_ID_INVALID_VARJO:
|
||||
return "XR_ERROR_MARKER_ID_INVALID_VARJO: The specified marker ID "
|
||||
"is not "
|
||||
"valid. (Added by the XR_VARJO_marker_tracking extension)";
|
||||
case XR_ERROR_MARKER_DETECTOR_PERMISSION_DENIED_ML:
|
||||
return "XR_ERROR_MARKER_DETECTOR_PERMISSION_DENIED_ML: The "
|
||||
"com.magicleap.permission.MARKER_TRACKING permission was "
|
||||
"denied. "
|
||||
"(Added by the XR_ML_marker_understanding extension)";
|
||||
case XR_ERROR_MARKER_DETECTOR_LOCATE_FAILED_ML:
|
||||
return "XR_ERROR_MARKER_DETECTOR_LOCATE_FAILED_ML: The specified "
|
||||
"marker "
|
||||
"could not be located spatially. (Added by the "
|
||||
"XR_ML_marker_understanding extension)";
|
||||
case XR_ERROR_MARKER_DETECTOR_INVALID_DATA_QUERY_ML:
|
||||
return "XR_ERROR_MARKER_DETECTOR_INVALID_DATA_QUERY_ML: The marker "
|
||||
"queried does not contain data of the requested type. "
|
||||
"(Added by "
|
||||
"the XR_ML_marker_understanding extension)";
|
||||
case XR_ERROR_MARKER_DETECTOR_INVALID_CREATE_INFO_ML:
|
||||
return "XR_ERROR_MARKER_DETECTOR_INVALID_CREATE_INFO_ML: "
|
||||
"createInfo "
|
||||
"contains mutually exclusive parameters, such as setting "
|
||||
"XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_APRIL_TAG_ML with "
|
||||
"XR_MARKER_TYPE_ARUCO_ML. (Added by the "
|
||||
"XR_ML_marker_understanding extension)";
|
||||
case XR_ERROR_MARKER_INVALID_ML:
|
||||
return "XR_ERROR_MARKER_INVALID_ML: The marker id passed to the "
|
||||
"function "
|
||||
"was invalid. (Added by the XR_ML_marker_understanding "
|
||||
"extension)";
|
||||
case XR_ERROR_LOCALIZATION_MAP_INCOMPATIBLE_ML:
|
||||
return "XR_ERROR_LOCALIZATION_MAP_INCOMPATIBLE_ML: The "
|
||||
"localization map "
|
||||
"being imported is not compatible with current OS or mode. "
|
||||
"(Added "
|
||||
"by the XR_ML_localization_map extension)";
|
||||
case XR_ERROR_LOCALIZATION_MAP_UNAVAILABLE_ML:
|
||||
return "XR_ERROR_LOCALIZATION_MAP_UNAVAILABLE_ML: The localization "
|
||||
"map "
|
||||
"requested is not available. (Added by the "
|
||||
"XR_ML_localization_map "
|
||||
"extension)";
|
||||
case XR_ERROR_LOCALIZATION_MAP_FAIL_ML:
|
||||
return "XR_ERROR_LOCALIZATION_MAP_FAIL_ML: The map localization "
|
||||
"service "
|
||||
"failed to fulfill the request, retry later. (Added by the "
|
||||
"XR_ML_localization_map extension)";
|
||||
case XR_ERROR_LOCALIZATION_MAP_IMPORT_EXPORT_PERMISSION_DENIED_ML:
|
||||
return "XR_ERROR_LOCALIZATION_MAP_IMPORT_EXPORT_PERMISSION_DENIED_"
|
||||
"ML: "
|
||||
"The com.magicleap.permission.SPACE_IMPORT_EXPORT "
|
||||
"permission was "
|
||||
"denied. (Added by the XR_ML_localization_map extension)";
|
||||
case XR_ERROR_LOCALIZATION_MAP_PERMISSION_DENIED_ML:
|
||||
return "XR_ERROR_LOCALIZATION_MAP_PERMISSION_DENIED_ML: The "
|
||||
"com.magicleap.permission.SPACE_MANAGER permission was "
|
||||
"denied. "
|
||||
"(Added by the XR_ML_localization_map extension)";
|
||||
case XR_ERROR_LOCALIZATION_MAP_ALREADY_EXISTS_ML:
|
||||
return "XR_ERROR_LOCALIZATION_MAP_ALREADY_EXISTS_ML: The map being "
|
||||
"imported already exists in the system. (Added by the "
|
||||
"XR_ML_localization_map extension)";
|
||||
case XR_ERROR_LOCALIZATION_MAP_CANNOT_EXPORT_CLOUD_MAP_ML:
|
||||
return "XR_ERROR_LOCALIZATION_MAP_CANNOT_EXPORT_CLOUD_MAP_ML: The "
|
||||
"map "
|
||||
"localization service cannot export cloud based maps. "
|
||||
"(Added by "
|
||||
"the XR_ML_localization_map extension)";
|
||||
case XR_ERROR_SPATIAL_ANCHORS_PERMISSION_DENIED_ML:
|
||||
return "XR_ERROR_SPATIAL_ANCHORS_PERMISSION_DENIED_ML: The "
|
||||
"com.magicleap.permission.SPATIAL_ANCHOR permission was not "
|
||||
"granted. (Added by the XR_ML_spatial_anchors extension)";
|
||||
case XR_ERROR_SPATIAL_ANCHORS_NOT_LOCALIZED_ML:
|
||||
return "XR_ERROR_SPATIAL_ANCHORS_NOT_LOCALIZED_ML: Operation "
|
||||
"failed "
|
||||
"because the system is not localized into a localization "
|
||||
"map. "
|
||||
"(Added by the XR_ML_spatial_anchors extension)";
|
||||
case XR_ERROR_SPATIAL_ANCHORS_OUT_OF_MAP_BOUNDS_ML:
|
||||
return "XR_ERROR_SPATIAL_ANCHORS_OUT_OF_MAP_BOUNDS_ML: Operation "
|
||||
"failed "
|
||||
"because it is performed outside of the localization map. "
|
||||
"(Added "
|
||||
"by the XR_ML_spatial_anchors extension)";
|
||||
case XR_ERROR_SPATIAL_ANCHORS_SPACE_NOT_LOCATABLE_ML:
|
||||
return "XR_ERROR_SPATIAL_ANCHORS_SPACE_NOT_LOCATABLE_ML: Operation "
|
||||
"failed because the space referenced cannot be located. "
|
||||
"(Added by "
|
||||
"the XR_ML_spatial_anchors extension)";
|
||||
case XR_ERROR_SPATIAL_ANCHORS_ANCHOR_NOT_FOUND_ML:
|
||||
return "XR_ERROR_SPATIAL_ANCHORS_ANCHOR_NOT_FOUND_ML: The anchor "
|
||||
"references was not found. (Added by the "
|
||||
"XR_ML_spatial_anchors_storage extension)";
|
||||
case XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT:
|
||||
return "XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT: A spatial "
|
||||
"anchor "
|
||||
"was not found associated with the spatial anchor name "
|
||||
"provided "
|
||||
"(Added by the XR_MSFT_spatial_anchor_persistence "
|
||||
"extension)";
|
||||
case XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT:
|
||||
return "XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT: The spatial "
|
||||
"anchor "
|
||||
"name provided was not valid (Added by the "
|
||||
"XR_MSFT_spatial_anchor_persistence extension)";
|
||||
case XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB:
|
||||
return "XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB: Anchor import from "
|
||||
"cloud "
|
||||
"or export from device failed. (Added by the "
|
||||
"XR_FB_spatial_entity_sharing extension)";
|
||||
case XR_ERROR_SPACE_LOCALIZATION_FAILED_FB:
|
||||
return "XR_ERROR_SPACE_LOCALIZATION_FAILED_FB: Anchors were "
|
||||
"downloaded "
|
||||
"from the cloud but failed to be imported/aligned on the "
|
||||
"device. "
|
||||
"(Added by the XR_FB_spatial_entity_sharing extension)";
|
||||
case XR_ERROR_SPACE_NETWORK_TIMEOUT_FB:
|
||||
return "XR_ERROR_SPACE_NETWORK_TIMEOUT_FB: Timeout occurred while "
|
||||
"waiting for network request to complete. (Added by the "
|
||||
"XR_FB_spatial_entity_sharing extension)";
|
||||
case XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB:
|
||||
return "XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB: The network "
|
||||
"request "
|
||||
"failed. (Added by the XR_FB_spatial_entity_sharing "
|
||||
"extension)";
|
||||
case XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB:
|
||||
return "XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB: Cloud storage is "
|
||||
"required for this operation but is currently disabled. "
|
||||
"(Added by "
|
||||
"the XR_FB_spatial_entity_sharing extension)";
|
||||
case XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META:
|
||||
return "XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META: "
|
||||
"The "
|
||||
"provided data buffer did not match the required size. "
|
||||
"(Added by "
|
||||
"the XR_META_passthrough_color_lut extension)";
|
||||
case XR_ERROR_RENDER_MODEL_ID_INVALID_EXT:
|
||||
return "XR_ERROR_RENDER_MODEL_ID_INVALID_EXT: The render model ID "
|
||||
"is "
|
||||
"invalid. (Added by the XR_EXT_render_model extension)";
|
||||
case XR_ERROR_RENDER_MODEL_ASSET_UNAVAILABLE_EXT:
|
||||
return "XR_ERROR_RENDER_MODEL_ASSET_UNAVAILABLE_EXT: The render "
|
||||
"model "
|
||||
"asset is unavailable. (Added by the XR_EXT_render_model "
|
||||
"extension)";
|
||||
case XR_ERROR_RENDER_MODEL_GLTF_EXTENSION_REQUIRED_EXT:
|
||||
return "XR_ERROR_RENDER_MODEL_GLTF_EXTENSION_REQUIRED_EXT: A glTF "
|
||||
"extension is required. (Added by the XR_EXT_render_model "
|
||||
"extension)";
|
||||
case XR_ERROR_NOT_INTERACTION_RENDER_MODEL_EXT:
|
||||
return "XR_ERROR_NOT_INTERACTION_RENDER_MODEL_EXT: The provided "
|
||||
"XrRenderModelEXT was not created from a XrRenderModelIdEXT "
|
||||
"from "
|
||||
"[XR_EXT_interaction_render_model] (Added by the "
|
||||
"XR_EXT_interaction_render_model extension)";
|
||||
case XR_ERROR_HINT_ALREADY_SET_QCOM:
|
||||
return "XR_ERROR_HINT_ALREADY_SET_QCOM: Tracking optimization hint "
|
||||
"is "
|
||||
"already set for the domain. (Added by the "
|
||||
"XR_QCOM_tracking_optimization_settings extension)";
|
||||
case XR_ERROR_NOT_AN_ANCHOR_HTC:
|
||||
return "XR_ERROR_NOT_AN_ANCHOR_HTC: The provided space is valid "
|
||||
"but not "
|
||||
"an anchor. (Added by the XR_HTC_anchor extension)";
|
||||
case XR_ERROR_SPATIAL_ENTITY_ID_INVALID_BD:
|
||||
return "XR_ERROR_SPATIAL_ENTITY_ID_INVALID_BD: The spatial entity "
|
||||
"id is "
|
||||
"invalid. (Added by the XR_BD_spatial_sensing extension)";
|
||||
case XR_ERROR_SPATIAL_SENSING_SERVICE_UNAVAILABLE_BD:
|
||||
return "XR_ERROR_SPATIAL_SENSING_SERVICE_UNAVAILABLE_BD: The "
|
||||
"spatial "
|
||||
"sensing service is unavailable. (Added by the "
|
||||
"XR_BD_spatial_sensing extension)";
|
||||
case XR_ERROR_ANCHOR_NOT_SUPPORTED_FOR_ENTITY_BD:
|
||||
return "XR_ERROR_ANCHOR_NOT_SUPPORTED_FOR_ENTITY_BD: The spatial "
|
||||
"entity "
|
||||
"does not support anchor. (Added by the "
|
||||
"XR_BD_spatial_sensing "
|
||||
"extension)";
|
||||
case XR_ERROR_SCENE_CAPTURE_FAILURE_BD:
|
||||
return "XR_ERROR_SCENE_CAPTURE_FAILURE_BD: The scene capture is "
|
||||
"failed, "
|
||||
"for example exiting abnormally. (Added by the "
|
||||
"XR_BD_spatial_scene extension)";
|
||||
case XR_ERROR_SPACE_NOT_LOCATABLE_EXT:
|
||||
return "XR_ERROR_SPACE_NOT_LOCATABLE_EXT: The space passed to the "
|
||||
"function was not locatable. (Added by the "
|
||||
"XR_EXT_plane_detection "
|
||||
"extension)";
|
||||
case XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT:
|
||||
return "XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT: The "
|
||||
"permission "
|
||||
"for this resource was not granted. (Added by the "
|
||||
"XR_EXT_plane_detection extension)";
|
||||
case XR_ERROR_FUTURE_PENDING_EXT:
|
||||
return "XR_ERROR_FUTURE_PENDING_EXT: Returned by completion "
|
||||
"function to "
|
||||
"indicate future is not ready. (Added by the XR_EXT_future "
|
||||
"extension)";
|
||||
case XR_ERROR_FUTURE_INVALID_EXT:
|
||||
return "XR_ERROR_FUTURE_INVALID_EXT: Returned by completion "
|
||||
"function to "
|
||||
"indicate future is not valid. (Added by the XR_EXT_future "
|
||||
"extension)";
|
||||
case XR_ERROR_SYSTEM_NOTIFICATION_PERMISSION_DENIED_ML:
|
||||
return "XR_ERROR_SYSTEM_NOTIFICATION_PERMISSION_DENIED_ML: The "
|
||||
"com.magicleap.permission.SYSTEM_NOTIFICATION permission "
|
||||
"was not "
|
||||
"granted. (Added by the XR_ML_system_notifications "
|
||||
"extension)";
|
||||
case XR_ERROR_SYSTEM_NOTIFICATION_INCOMPATIBLE_SKU_ML:
|
||||
return "XR_ERROR_SYSTEM_NOTIFICATION_INCOMPATIBLE_SKU_ML: "
|
||||
"Incompatible "
|
||||
"SKU detected. (Added by the XR_ML_system_notifications "
|
||||
"extension)";
|
||||
case XR_ERROR_WORLD_MESH_DETECTOR_PERMISSION_DENIED_ML:
|
||||
return "XR_ERROR_WORLD_MESH_DETECTOR_PERMISSION_DENIED_ML: The "
|
||||
"world "
|
||||
"mesh detector permission was not granted. (Added by the "
|
||||
"XR_ML_world_mesh_detection extension)";
|
||||
case XR_ERROR_WORLD_MESH_DETECTOR_SPACE_NOT_LOCATABLE_ML:
|
||||
return "XR_ERROR_WORLD_MESH_DETECTOR_SPACE_NOT_LOCATABLE_ML: At "
|
||||
"the time "
|
||||
"of the call the runtime was unable to locate the space and "
|
||||
"cannot fulfill your request. (Added by the "
|
||||
"XR_ML_world_mesh_detection extension)";
|
||||
case XR_ERROR_COLOCATION_DISCOVERY_NETWORK_FAILED_META:
|
||||
return "XR_ERROR_COLOCATION_DISCOVERY_NETWORK_FAILED_META: The "
|
||||
"network "
|
||||
"request failed. (Added by the XR_META_colocation_discovery "
|
||||
"extension)";
|
||||
case XR_ERROR_COLOCATION_DISCOVERY_NO_DISCOVERY_METHOD_META:
|
||||
return "XR_ERROR_COLOCATION_DISCOVERY_NO_DISCOVERY_METHOD_META: "
|
||||
"The "
|
||||
"runtime does not have any methods available to perform "
|
||||
"discovery. (Added by the XR_META_colocation_discovery "
|
||||
"extension)";
|
||||
case XR_ERROR_SPACE_GROUP_NOT_FOUND_META:
|
||||
return "XR_ERROR_SPACE_GROUP_NOT_FOUND_META: The group UUID was "
|
||||
"not "
|
||||
"found within the runtime (Added by the "
|
||||
"XR_META_spatial_entity_group_sharing extension)";
|
||||
case XR_ERROR_SPATIAL_CAPABILITY_UNSUPPORTED_EXT:
|
||||
return "XR_ERROR_SPATIAL_CAPABILITY_UNSUPPORTED_EXT: The specified "
|
||||
"spatial capability is not supported by the runtime or the "
|
||||
"system. (Added by the XR_EXT_spatial_entity extension)";
|
||||
case XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT:
|
||||
return "XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT: The specified "
|
||||
"spatial "
|
||||
"entity id is invalid or an entity with that id does not "
|
||||
"exist in "
|
||||
"the environment. (Added by the XR_EXT_spatial_entity "
|
||||
"extension)";
|
||||
case XR_ERROR_SPATIAL_BUFFER_ID_INVALID_EXT:
|
||||
return "XR_ERROR_SPATIAL_BUFFER_ID_INVALID_EXT: The specified "
|
||||
"spatial "
|
||||
"buffer id is invalid or does not exist in the spatial "
|
||||
"snapshot "
|
||||
"being used to query for the buffer data. (Added by the "
|
||||
"XR_EXT_spatial_entity extension)";
|
||||
case XR_ERROR_SPATIAL_COMPONENT_UNSUPPORTED_FOR_CAPABILITY_EXT:
|
||||
return "XR_ERROR_SPATIAL_COMPONENT_UNSUPPORTED_FOR_CAPABILITY_EXT: "
|
||||
"The "
|
||||
"specified spatial component is not supported by the "
|
||||
"runtime or "
|
||||
"the system for the given capability. (Added by the "
|
||||
"XR_EXT_spatial_entity extension)";
|
||||
case XR_ERROR_SPATIAL_CAPABILITY_CONFIGURATION_INVALID_EXT:
|
||||
return "XR_ERROR_SPATIAL_CAPABILITY_CONFIGURATION_INVALID_EXT: The "
|
||||
"specified spatial capability configuration is invalid. "
|
||||
"(Added by "
|
||||
"the XR_EXT_spatial_entity extension)";
|
||||
case XR_ERROR_SPATIAL_COMPONENT_NOT_ENABLED_EXT:
|
||||
return "XR_ERROR_SPATIAL_COMPONENT_NOT_ENABLED_EXT: The specified "
|
||||
"spatial component is not enabled for the spatial context. "
|
||||
"(Added "
|
||||
"by the XR_EXT_spatial_entity extension)";
|
||||
case XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT:
|
||||
return "XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT: The "
|
||||
"specified spatial persistence scope is not supported by "
|
||||
"the "
|
||||
"runtime or the system. (Added by the "
|
||||
"XR_EXT_spatial_persistence "
|
||||
"extension)";
|
||||
case XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_INCOMPATIBLE_EXT:
|
||||
return "XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_INCOMPATIBLE_EXT: THe "
|
||||
"scope "
|
||||
"configured for the persistence context is incompatible for "
|
||||
"the "
|
||||
"current spatial entity. (Added by the "
|
||||
"XR_EXT_spatial_persistence_operations extension)";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
template<class FmtCtx> auto format(XrResult r, FmtCtx &ctx) const
|
||||
{
|
||||
if (spec == 'd') {
|
||||
return format_to(ctx.out(), "{}", static_cast<int32_t>(r));
|
||||
}
|
||||
|
||||
std::string_view str = std::formatter<XrResult, char>::to_string(r);
|
||||
if (!str.empty()) {
|
||||
return format_to(ctx.out(), "{}", str);
|
||||
}
|
||||
|
||||
return format_to(ctx.out(), "<0x{:x}>", static_cast<uint32_t>(r));
|
||||
}
|
||||
|
||||
private:
|
||||
char spec { 's' };
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
6
src/common.h
Normal file
6
src/common.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#define ARRAY_SZ(arr) (sizeof(arr) / sizeof(*arr))
|
||||
|
||||
#endif // COMMON_H
|
||||
@@ -1,705 +0,0 @@
|
||||
#include "dhos_config.h"
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <charconv>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <print>
|
||||
#include <sstream>
|
||||
|
||||
namespace dhos {
|
||||
|
||||
// environment shared across parser and evaluation
|
||||
struct Environment {
|
||||
Environment(Environment *p = nullptr)
|
||||
: parent { p }
|
||||
{
|
||||
}
|
||||
std::unordered_map<std::string, Value> tbl;
|
||||
Environment *parent;
|
||||
bool contains(std::string const &k) const
|
||||
{
|
||||
return tbl.contains(k) || (parent && parent->contains(k));
|
||||
}
|
||||
Value &operator[](std::string const &k)
|
||||
{
|
||||
if (tbl.contains(k))
|
||||
return tbl.at(k);
|
||||
if (parent)
|
||||
return (*parent)[k];
|
||||
throw std::runtime_error(std::format("Undefined variable: {}", k));
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
// env, lexer, parser
|
||||
|
||||
enum class Tok {
|
||||
End,
|
||||
Id,
|
||||
Num,
|
||||
Str,
|
||||
Path,
|
||||
LPar,
|
||||
RPar,
|
||||
LBr,
|
||||
RBr,
|
||||
LBrk,
|
||||
RBrk,
|
||||
Eq,
|
||||
Dot,
|
||||
Comma
|
||||
};
|
||||
|
||||
std::string Tok_str(Tok t)
|
||||
{
|
||||
if (t == Tok::End)
|
||||
return "End";
|
||||
else if (t == Tok::Id)
|
||||
return "Id";
|
||||
else if (t == Tok::Num)
|
||||
return "Num";
|
||||
else if (t == Tok::Str)
|
||||
return "Str";
|
||||
else if (t == Tok::Path)
|
||||
return "Path";
|
||||
else if (t == Tok::LPar)
|
||||
return "LPar";
|
||||
else if (t == Tok::RPar)
|
||||
return "RPar";
|
||||
else if (t == Tok::LBr)
|
||||
return "LBr";
|
||||
else if (t == Tok::RBr)
|
||||
return "RBr";
|
||||
else if (t == Tok::LBrk)
|
||||
return "LBrk";
|
||||
else if (t == Tok::RBrk)
|
||||
return "RBrk";
|
||||
else if (t == Tok::Eq)
|
||||
return "Eq";
|
||||
else if (t == Tok::Dot)
|
||||
return "Dot";
|
||||
else if (t == Tok::Comma)
|
||||
return "Comma";
|
||||
else
|
||||
return "?";
|
||||
}
|
||||
|
||||
struct T {
|
||||
Tok k;
|
||||
std::string t;
|
||||
};
|
||||
|
||||
class Lex {
|
||||
public:
|
||||
explicit Lex(std::string_view s)
|
||||
: src { s }
|
||||
{
|
||||
}
|
||||
T next();
|
||||
|
||||
private:
|
||||
T id();
|
||||
T num();
|
||||
T str();
|
||||
T path();
|
||||
void skip();
|
||||
std::string_view src;
|
||||
std::size_t pos {};
|
||||
};
|
||||
|
||||
T Lex::id()
|
||||
{
|
||||
std::size_t s = pos;
|
||||
while (pos < src.size()
|
||||
&& (std::isalnum((unsigned char)src[pos]) || src[pos] == '_'))
|
||||
++pos;
|
||||
return { Tok::Id, std::string { src.substr(s, pos - s) } };
|
||||
}
|
||||
T Lex::num()
|
||||
{
|
||||
std::size_t s = pos;
|
||||
while (pos < src.size()
|
||||
&& (std::isdigit((unsigned char)src[pos]) || src[pos] == '_'))
|
||||
++pos;
|
||||
if (pos < src.size() && src[pos] == '.') {
|
||||
++pos;
|
||||
while (pos < src.size()
|
||||
&& (std::isdigit((unsigned char)src[pos]) || src[pos] == '_'))
|
||||
++pos;
|
||||
}
|
||||
return { Tok::Num, std::string { src.substr(s, pos - s) } };
|
||||
}
|
||||
T Lex::str()
|
||||
{
|
||||
char q = src[pos++];
|
||||
std::string o;
|
||||
while (pos < src.size() && src[pos] != q)
|
||||
o.push_back(src[pos++]);
|
||||
if (pos >= src.size())
|
||||
throw std::runtime_error("Unterminated string literal");
|
||||
++pos;
|
||||
return { Tok::Str, o };
|
||||
}
|
||||
|
||||
static bool is_path_ch(char c)
|
||||
{
|
||||
return std::isalnum((unsigned char)c) || c == '_' || c == '.' || c == '/'
|
||||
|| c == '-' || c == ':';
|
||||
}
|
||||
|
||||
T Lex::path()
|
||||
{
|
||||
std::string out;
|
||||
while (pos < src.size()) {
|
||||
char c = src[pos];
|
||||
if (c == '\\') {
|
||||
++pos;
|
||||
if (pos < src.size()) {
|
||||
out.push_back(src[pos]);
|
||||
++pos;
|
||||
} else {
|
||||
out.push_back('\\');
|
||||
}
|
||||
} else if (is_path_ch(c)) {
|
||||
out.push_back(c);
|
||||
++pos;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { Tok::Path, out };
|
||||
}
|
||||
|
||||
void Lex::skip()
|
||||
{
|
||||
while (pos < src.size()) {
|
||||
if (std::isspace((unsigned char)src[pos])) {
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
if (src[pos] == '#') {
|
||||
while (pos < src.size() && src[pos] != '\n')
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
T Lex::next()
|
||||
{
|
||||
skip();
|
||||
if (pos >= src.size())
|
||||
return { Tok::End, "" };
|
||||
char c = src[pos];
|
||||
|
||||
if (c == '/' // "/foo"
|
||||
|| (c == '.' && pos + 1 < src.size() && src[pos + 1] == '/') // "./foo"
|
||||
|| (c == '.' && pos + 2 < src.size() && src[pos + 1] == '.'
|
||||
&& src[pos + 2] == '/') // "../foo"
|
||||
|| (std::isalpha((unsigned char)c) && pos + 1 < src.size()
|
||||
&& src[pos + 1] == ':')) // "C:/foo"
|
||||
return path();
|
||||
|
||||
switch (c) {
|
||||
case '(':
|
||||
++pos;
|
||||
return { Tok::LPar, "(" };
|
||||
case ')':
|
||||
++pos;
|
||||
return { Tok::RPar, ")" };
|
||||
case '{':
|
||||
++pos;
|
||||
return { Tok::LBr, "{" };
|
||||
case '}':
|
||||
++pos;
|
||||
return { Tok::RBr, "}" };
|
||||
case '[':
|
||||
++pos;
|
||||
return { Tok::LBrk, "[" };
|
||||
case ']':
|
||||
++pos;
|
||||
return { Tok::RBrk, "]" };
|
||||
case '=':
|
||||
++pos;
|
||||
return { Tok::Eq, "=" };
|
||||
case '.':
|
||||
++pos;
|
||||
return { Tok::Dot, "." };
|
||||
case ',':
|
||||
++pos;
|
||||
return { Tok::Comma, "," };
|
||||
case '"':
|
||||
case '\'':
|
||||
return str();
|
||||
case 0:
|
||||
return { Tok::End, "" };
|
||||
default:
|
||||
if (std::isdigit((unsigned char)c))
|
||||
return num();
|
||||
if (std::isalpha((unsigned char)c) || c == '_')
|
||||
return id();
|
||||
std::println("Invalid character: {} ({:d})", c, c);
|
||||
throw std::runtime_error(std::format("Invalid character: {}", c));
|
||||
}
|
||||
}
|
||||
|
||||
// parser
|
||||
class Parser {
|
||||
public:
|
||||
Parser(std::string_view s, std::shared_ptr<Environment> e)
|
||||
: lx { s }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
adv();
|
||||
}
|
||||
Value parse() { return val(); }
|
||||
|
||||
private:
|
||||
Lex lx;
|
||||
T cur;
|
||||
std::shared_ptr<Environment> env;
|
||||
void adv() { cur = lx.next(); }
|
||||
bool acc(Tok k)
|
||||
{
|
||||
if (cur.k == k) {
|
||||
adv();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void exp(Tok k)
|
||||
{
|
||||
if (!acc(k)) {
|
||||
std::println("Expected: {}, Got: {}", Tok_str(k), Tok_str(cur.k));
|
||||
throw std::runtime_error(
|
||||
std::format("Syntax error: expected {}, got {}", Tok_str(k),
|
||||
Tok_str(cur.k)));
|
||||
}
|
||||
}
|
||||
bool begins(Tok k)
|
||||
{
|
||||
return k == Tok::Path || k == Tok::Id || k == Tok::Num || k == Tok::Str
|
||||
|| k == Tok::LBr || k == Tok::LBrk || k == Tok::LPar;
|
||||
}
|
||||
std::string id()
|
||||
{
|
||||
std::string s = cur.t;
|
||||
exp(Tok::Id);
|
||||
return s;
|
||||
}
|
||||
|
||||
Value array()
|
||||
{
|
||||
exp(Tok::LBrk);
|
||||
Array a;
|
||||
while (cur.k != Tok::RBrk) {
|
||||
a.push_back(val());
|
||||
acc(Tok::Comma);
|
||||
}
|
||||
exp(Tok::RBrk);
|
||||
return Value { std::move(a), env };
|
||||
}
|
||||
Value block()
|
||||
{
|
||||
exp(Tok::LBr);
|
||||
Object o;
|
||||
while (cur.k != Tok::RBr) {
|
||||
if (acc(Tok::LPar)) {
|
||||
Value inner = val();
|
||||
exp(Tok::RPar);
|
||||
o.insert(inner.obj().begin(), inner.obj().end());
|
||||
continue;
|
||||
}
|
||||
std::string k = id();
|
||||
exp(Tok::Eq);
|
||||
o[k] = val();
|
||||
}
|
||||
exp(Tok::RBr);
|
||||
return Value { std::move(o), env };
|
||||
}
|
||||
Value func()
|
||||
{
|
||||
exp(Tok::Id);
|
||||
std::vector<std::string> params;
|
||||
while (cur.k == Tok::Id)
|
||||
params.push_back(id());
|
||||
exp(Tok::Eq);
|
||||
Value body = val();
|
||||
auto f = std::make_shared<Value::Function>();
|
||||
f->params = params;
|
||||
f->body = std::make_shared<Value>(body);
|
||||
return Value { std::move(f), env };
|
||||
}
|
||||
Value call()
|
||||
{
|
||||
std::string name = id();
|
||||
std::vector<Value> args;
|
||||
while (begins(cur.k))
|
||||
args.emplace_back(val());
|
||||
auto c = std::make_shared<Value::Call>();
|
||||
c->name = name;
|
||||
c->args = std::move(args);
|
||||
return Value { std::move(c), env };
|
||||
}
|
||||
Value val()
|
||||
{
|
||||
switch (cur.k) {
|
||||
case Tok::Id:
|
||||
if (cur.t == "fn") {
|
||||
return func();
|
||||
}
|
||||
if (cur.t == "nil") {
|
||||
adv();
|
||||
return Value { env };
|
||||
}
|
||||
{
|
||||
std::string idn = cur.t;
|
||||
adv();
|
||||
|
||||
// make the base AST node
|
||||
auto node = std::make_shared<Value::Call>();
|
||||
node->recv = nullptr; // top‐level call
|
||||
node->name = std::move(idn);
|
||||
|
||||
// consume any “.field” chains
|
||||
while (acc(Tok::Dot)) {
|
||||
auto parent = node;
|
||||
std::string fld = id();
|
||||
auto mnode = std::make_shared<Value::Call>();
|
||||
mnode->recv = std::make_shared<Value>(
|
||||
parent, env); // wrap the old AST
|
||||
mnode->name = std::move(fld);
|
||||
node = mnode;
|
||||
}
|
||||
|
||||
// then any args
|
||||
while (begins(cur.k)) {
|
||||
node->args.push_back(val());
|
||||
}
|
||||
|
||||
return Value { node, env };
|
||||
}
|
||||
case Tok::Num: {
|
||||
std::string s = cur.t;
|
||||
s.erase(std::remove(s.begin(), s.end(), '_'), s.end());
|
||||
double n;
|
||||
if (static_cast<int>(
|
||||
std::from_chars(s.data(), s.data() + s.size(), n).ec))
|
||||
throw;
|
||||
adv();
|
||||
return Value { n, env };
|
||||
}
|
||||
case Tok::Str: {
|
||||
Value v { cur.t, env };
|
||||
adv();
|
||||
return v;
|
||||
}
|
||||
case Tok::Path: {
|
||||
Value v { std::filesystem::path { cur.t }, env };
|
||||
adv();
|
||||
return v;
|
||||
}
|
||||
case Tok::LBrk:
|
||||
return array();
|
||||
case Tok::LBr:
|
||||
return block();
|
||||
case Tok::LPar:
|
||||
adv();
|
||||
{
|
||||
Value v = val();
|
||||
exp(Tok::RPar);
|
||||
return v;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
std::format("Unexpected token: {}", Tok_str(cur.k)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// built-ins
|
||||
Value join(Array const &a)
|
||||
{
|
||||
Array r;
|
||||
for (auto &v : a) {
|
||||
if (!v.is_arr())
|
||||
throw;
|
||||
r.insert(r.end(), v.arr().begin(), v.arr().end());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
Value list_rng(Array const &a)
|
||||
{
|
||||
if (a.size() != 3 || !a[0].is_num() || !a[1].is_num() || !a[2].is_num())
|
||||
throw;
|
||||
double s = a[0].num(), e = a[1].num(), st = a[2].num();
|
||||
if (!st)
|
||||
throw;
|
||||
Array r;
|
||||
if (st > 0)
|
||||
for (double x = s; x <= e; x += st)
|
||||
r.emplace_back(x);
|
||||
else
|
||||
for (double x = s; x >= e; x += st)
|
||||
r.emplace_back(x);
|
||||
return r;
|
||||
}
|
||||
Value imp(Array const &a)
|
||||
{
|
||||
if (a.empty())
|
||||
throw;
|
||||
std::ifstream f;
|
||||
if (a[0].is_str()) {
|
||||
f = std::ifstream { a[0].str() };
|
||||
} else if (a[0].is_path()) {
|
||||
f = std::ifstream { a[0].path() };
|
||||
} else {
|
||||
throw;
|
||||
}
|
||||
if (!f)
|
||||
throw;
|
||||
std::stringstream b;
|
||||
b << f.rdbuf();
|
||||
std::istringstream in { b.str() };
|
||||
return parse_config(in);
|
||||
}
|
||||
|
||||
// serializer
|
||||
void w(std::ostream &o, Value const &v)
|
||||
{
|
||||
if (v.is_nil()) {
|
||||
o << "nil";
|
||||
return;
|
||||
}
|
||||
if (v.is_num()) {
|
||||
o << v.num();
|
||||
return;
|
||||
}
|
||||
if (v.is_str()) {
|
||||
o << '"' << v.str() << '"';
|
||||
return;
|
||||
}
|
||||
if (v.is_path()) {
|
||||
o << v.path().generic_string();
|
||||
return;
|
||||
}
|
||||
if (v.is_arr()) {
|
||||
o << "[";
|
||||
bool f = true;
|
||||
for (auto &x : v.arr()) {
|
||||
if (!f)
|
||||
o << ",";
|
||||
w(o, x);
|
||||
f = false;
|
||||
}
|
||||
o << "]";
|
||||
return;
|
||||
}
|
||||
if (v.is_obj()) {
|
||||
o << "{";
|
||||
bool f = true;
|
||||
for (auto &[k, x] : v.obj()) {
|
||||
if (!f)
|
||||
o << ",";
|
||||
o << k << "=";
|
||||
w(o, x);
|
||||
f = false;
|
||||
}
|
||||
o << "}";
|
||||
return;
|
||||
}
|
||||
o << "fn"; // prints literal token for functions
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// public helpers
|
||||
Value eval(Value const &v, Object const *extra_lib)
|
||||
{
|
||||
static Object base = make_default_lib();
|
||||
Object merged = merge_lib(base, extra_lib);
|
||||
|
||||
if (v.is_call()) {
|
||||
auto const &c = v.call();
|
||||
Value fn;
|
||||
|
||||
// receiver or global
|
||||
if (c.recv && !c.recv->is_nil()) {
|
||||
Value recv = eval(*c.recv, extra_lib);
|
||||
fn = recv[c.name];
|
||||
} else {
|
||||
if (auto it = merged.find(c.name); it != merged.end())
|
||||
fn = it->second;
|
||||
else
|
||||
fn = (*v.env)[c.name];
|
||||
}
|
||||
|
||||
// args
|
||||
Array argv;
|
||||
argv.reserve(c.args.size());
|
||||
for (auto &a : c.args)
|
||||
argv.push_back(eval(a, extra_lib));
|
||||
|
||||
// call
|
||||
if (auto b = std::get_if<Builtin>(&fn.data))
|
||||
return (*b)(argv);
|
||||
|
||||
if (auto fp = std::get_if<std::shared_ptr<Value::Function>>(&fn.data)) {
|
||||
auto child = std::make_shared<Environment>(fn.env.get());
|
||||
for (size_t i = 0; i < (*fp)->params.size(); ++i)
|
||||
child->tbl[(*fp)->params[i]]
|
||||
= i < argv.size() ? argv[i] : Value(child);
|
||||
|
||||
Value body = *(*fp)->body;
|
||||
body.env = child;
|
||||
return eval(body, extra_lib);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
// not a call
|
||||
if (!v.is_fn())
|
||||
return v;
|
||||
|
||||
if (auto fp = std::get_if<std::shared_ptr<Value::Function>>(&v.data))
|
||||
return *(*fp)->body;
|
||||
|
||||
return v; // builtin with no args
|
||||
}
|
||||
|
||||
// auto-evaluating operator[] impl
|
||||
static void materialise(Value &v)
|
||||
{
|
||||
auto r = eval(v, nullptr);
|
||||
if (!r.is_fn() && !r.is_call())
|
||||
v = std::move(r);
|
||||
}
|
||||
|
||||
Value &Value::operator[](std::string const &k)
|
||||
{
|
||||
materialise(*this);
|
||||
if (is_nil())
|
||||
return *this;
|
||||
if (!is_obj())
|
||||
throw std::logic_error("[] on non-object");
|
||||
|
||||
Value &child = obj()[k];
|
||||
materialise(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
Value &Value::operator[](std::size_t i)
|
||||
{
|
||||
materialise(*this);
|
||||
if (is_nil())
|
||||
return *this;
|
||||
if (!is_arr())
|
||||
throw std::logic_error("[] on non-array");
|
||||
if (i >= arr().size())
|
||||
throw std::out_of_range("index");
|
||||
|
||||
Value &child = arr()[i];
|
||||
materialise(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
Value const &Value::operator[](std::string const &k) const
|
||||
{
|
||||
return const_cast<Value *>(this)->operator[](k);
|
||||
}
|
||||
Value const &Value::operator[](std::size_t i) const
|
||||
{
|
||||
return const_cast<Value *>(this)->operator[](i);
|
||||
}
|
||||
|
||||
// parse/write
|
||||
Value parse_config(std::istream &in)
|
||||
{
|
||||
std::stringstream b;
|
||||
b << in.rdbuf();
|
||||
std::string src = b.str();
|
||||
auto env = std::make_shared<Environment>();
|
||||
env->tbl = make_default_lib();
|
||||
Parser p { src, env };
|
||||
return p.parse();
|
||||
}
|
||||
inline void resolve_paths(Value &v, std::filesystem::path const &base)
|
||||
{
|
||||
if (v.is_path()) {
|
||||
auto &p = v.path();
|
||||
if (p.is_relative())
|
||||
p = base / p;
|
||||
return;
|
||||
}
|
||||
if (v.is_arr()) {
|
||||
for (auto &x : v.arr())
|
||||
resolve_paths(x, base);
|
||||
return;
|
||||
}
|
||||
if (v.is_obj()) {
|
||||
for (auto &[_, x] : v.obj())
|
||||
resolve_paths(x, base);
|
||||
return;
|
||||
}
|
||||
if (v.is_call()) {
|
||||
for (auto &x : v.call().args)
|
||||
resolve_paths(x, base);
|
||||
}
|
||||
if (std::holds_alternative<std::shared_ptr<Value::Function>>(v.data)) {
|
||||
resolve_paths(
|
||||
*std::get<std::shared_ptr<Value::Function>>(v.data)->body, base);
|
||||
}
|
||||
}
|
||||
|
||||
Value parse_config(std::filesystem::path const &f)
|
||||
{
|
||||
std::ifstream in { f };
|
||||
if (!in)
|
||||
throw std::runtime_error(
|
||||
std::format("Failed to open configuration file: {}", f.string()));
|
||||
Value v = parse_config(in);
|
||||
resolve_paths(v, f.parent_path());
|
||||
return v;
|
||||
}
|
||||
void write_config(Value const &v, std::filesystem::path const &o)
|
||||
{
|
||||
std::ofstream f { o };
|
||||
if (!f)
|
||||
throw std::runtime_error(
|
||||
std::format("Failed to write configuration file: {}", o.string()));
|
||||
w(f, v);
|
||||
}
|
||||
|
||||
// default lib
|
||||
Object make_default_lib();
|
||||
Object merge_lib(Object const &base, Object const *extra)
|
||||
{
|
||||
Object out = base;
|
||||
if (extra)
|
||||
out.insert(extra->begin(), extra->end());
|
||||
return out;
|
||||
}
|
||||
|
||||
auto get_env_tbl(Environment *env) -> std::unordered_map<std::string, Value> &
|
||||
{
|
||||
return env->tbl;
|
||||
}
|
||||
|
||||
Object make_default_lib()
|
||||
{
|
||||
Object l;
|
||||
l["join"] = Builtin { join };
|
||||
l["list_from_range"] = Builtin { list_rng };
|
||||
l["import"] = Builtin { imp };
|
||||
return l;
|
||||
}
|
||||
|
||||
} // namespace dhos
|
||||
|
||||
// NOLINTEND
|
||||
@@ -1,149 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace dhos {
|
||||
|
||||
struct Environment;
|
||||
struct Value;
|
||||
|
||||
using Array = std::vector<Value>;
|
||||
using Object = std::unordered_map<std::string, Value>;
|
||||
using Builtin = std::function<Value(Array const &)>;
|
||||
|
||||
struct Value {
|
||||
using EnvPtr = std::shared_ptr<Environment>;
|
||||
|
||||
struct Function {
|
||||
std::vector<std::string> params;
|
||||
std::shared_ptr<Value> body;
|
||||
};
|
||||
struct Call {
|
||||
std::string name;
|
||||
Array args;
|
||||
std::shared_ptr<Value> recv;
|
||||
};
|
||||
using Data = std::variant<std::monostate, double, std::string,
|
||||
std::filesystem::path, Array, Object, std::shared_ptr<Function>,
|
||||
Builtin, std::shared_ptr<Call>>;
|
||||
Data data {};
|
||||
EnvPtr env {};
|
||||
|
||||
Value() = default;
|
||||
explicit Value(EnvPtr e)
|
||||
: env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(double n, EnvPtr e = {})
|
||||
: data { n }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(std::string const &s, EnvPtr e = {})
|
||||
: data { s }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(char const *s, EnvPtr e = {})
|
||||
: data { std::string { s } }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(std::filesystem::path const &p, EnvPtr e = {})
|
||||
: data { p }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(Array a, EnvPtr e = {})
|
||||
: data { std::move(a) }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(Object o, EnvPtr e = {})
|
||||
: data { std::move(o) }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(std::shared_ptr<Function> f, EnvPtr e = {})
|
||||
: data { std::move(f) }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(Builtin b, EnvPtr e = {})
|
||||
: data { std::move(b) }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
Value(std::shared_ptr<Call> c, EnvPtr e = {})
|
||||
: data { std::move(c) }
|
||||
, env { std::move(e) }
|
||||
{
|
||||
}
|
||||
|
||||
bool is_nil() const { return std::holds_alternative<std::monostate>(data); }
|
||||
bool is_num() const { return std::holds_alternative<double>(data); }
|
||||
bool is_str() const { return std::holds_alternative<std::string>(data); }
|
||||
bool is_path() const
|
||||
{
|
||||
return std::holds_alternative<std::filesystem::path>(data);
|
||||
}
|
||||
bool is_arr() const { return std::holds_alternative<Array>(data); }
|
||||
bool is_obj() const { return std::holds_alternative<Object>(data); }
|
||||
bool is_fn() const
|
||||
{
|
||||
return std::holds_alternative<std::shared_ptr<Function>>(data)
|
||||
|| std::holds_alternative<Builtin>(data);
|
||||
}
|
||||
bool is_call() const
|
||||
{
|
||||
return std::holds_alternative<std::shared_ptr<Call>>(data);
|
||||
}
|
||||
|
||||
double num() const { return std::get<double>(data); }
|
||||
std::string const &str() const { return std::get<std::string>(data); }
|
||||
Array &arr() { return std::get<Array>(data); }
|
||||
Array const &arr() const { return std::get<Array>(data); }
|
||||
Object &obj() { return std::get<Object>(data); }
|
||||
Object const &obj() const { return std::get<Object>(data); }
|
||||
std::filesystem::path &path()
|
||||
{
|
||||
return std::get<std::filesystem::path>(data);
|
||||
}
|
||||
std::filesystem::path const &path() const
|
||||
{
|
||||
return std::get<std::filesystem::path>(data);
|
||||
}
|
||||
Call &call() { return *std::get<std::shared_ptr<Call>>(data); }
|
||||
Call const &call() const { return *std::get<std::shared_ptr<Call>>(data); }
|
||||
|
||||
// auto-evaluating nlohmann-style access
|
||||
Value &operator[](std::string const &k);
|
||||
Value &operator[](std::size_t i);
|
||||
Value const &operator[](std::string const &k) const;
|
||||
Value const &operator[](std::size_t i) const;
|
||||
};
|
||||
|
||||
// pure evaluation helper (never mutates its argument)
|
||||
Value eval(Value const &v, Object const *extra_lib = nullptr);
|
||||
|
||||
Value parse_config(std::istream &in);
|
||||
Value parse_config(std::filesystem::path const &f);
|
||||
void write_config(Value const &v, std::filesystem::path const &out);
|
||||
|
||||
Object make_default_lib();
|
||||
Object merge_lib(Object const &base, Object const *extra);
|
||||
|
||||
auto get_env_tbl(Environment *env) -> std::unordered_map<std::string, Value> &;
|
||||
|
||||
} // namespace dhos
|
||||
|
||||
// NOLINTEND
|
||||
16
src/main.c
Normal file
16
src/main.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "LunarWM.h"
|
||||
|
||||
LunarWM g_wm = {};
|
||||
|
||||
void sigint_handler(int) { LunarWM_terminate(&g_wm); }
|
||||
|
||||
int main(void)
|
||||
{
|
||||
assert(LunarWM_init(&g_wm));
|
||||
signal(SIGINT, sigint_handler);
|
||||
LunarWM_run(&g_wm);
|
||||
LunarWM_destroy(&g_wm);
|
||||
}
|
||||
30
src/main.cpp
30
src/main.cpp
@@ -1,30 +0,0 @@
|
||||
// NOLINTBEGIN
|
||||
#include <cassert>
|
||||
#include <csignal>
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include <cpptrace/from_current.hpp>
|
||||
// NOLINTEND
|
||||
|
||||
import std;
|
||||
|
||||
import LunarWM.LunarWM;
|
||||
|
||||
static std::unique_ptr<LunarWM::LunarWM> g_comp;
|
||||
|
||||
auto main() noexcept -> int // NOLINT(bugprone-exception-escape)
|
||||
{
|
||||
CPPTRACE_TRY
|
||||
{
|
||||
g_comp = std::make_unique<LunarWM::LunarWM>();
|
||||
g_comp->init();
|
||||
assert(
|
||||
std::signal(SIGINT, [](int) { g_comp->terminate(); }) != SIG_ERR);
|
||||
g_comp->run();
|
||||
}
|
||||
CPPTRACE_CATCH(std::exception const &e)
|
||||
{
|
||||
std::println(std::cerr, "Uncaught exception: {}", e.what());
|
||||
cpptrace::from_current_exception().print();
|
||||
}
|
||||
}
|
||||
148
src/vec.c
Normal file
148
src/vec.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2024, Mashpoe
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "vec.h"
|
||||
#include <string.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec_size_t size;
|
||||
vec_size_t capacity;
|
||||
unsigned char data[];
|
||||
} vector_header;
|
||||
|
||||
vector_header* vector_get_header(vector vec) { return &((vector_header*)vec)[-1]; }
|
||||
|
||||
vector vector_create(void)
|
||||
{
|
||||
vector_header* h = (vector_header*)malloc(sizeof(vector_header));
|
||||
h->capacity = 0;
|
||||
h->size = 0;
|
||||
|
||||
return &h->data;
|
||||
}
|
||||
|
||||
void vector_free(vector vec) { free(vector_get_header(vec)); }
|
||||
|
||||
vec_size_t vector_size(vector vec) { return vector_get_header(vec)->size; }
|
||||
|
||||
vec_size_t vector_capacity(vector vec) { return vector_get_header(vec)->capacity; }
|
||||
|
||||
vector_header* vector_realloc(vector_header* h, vec_type_t type_size)
|
||||
{
|
||||
vec_size_t new_capacity = (h->capacity == 0) ? 1 : h->capacity * 2;
|
||||
vector_header* new_h = (vector_header*)realloc(h, sizeof(vector_header) + new_capacity * type_size);
|
||||
new_h->capacity = new_capacity;
|
||||
|
||||
return new_h;
|
||||
}
|
||||
|
||||
bool vector_has_space(vector_header* h)
|
||||
{
|
||||
return h->capacity - h->size > 0;
|
||||
}
|
||||
|
||||
void* _vector_add_dst(vector* vec_addr, vec_type_t type_size)
|
||||
{
|
||||
vector_header* h = vector_get_header(*vec_addr);
|
||||
|
||||
if (!vector_has_space(h))
|
||||
{
|
||||
h = vector_realloc(h, type_size);
|
||||
*vec_addr = h->data;
|
||||
}
|
||||
|
||||
return &h->data[type_size * h->size++];
|
||||
}
|
||||
|
||||
void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos)
|
||||
{
|
||||
vector_header* h = vector_get_header(*vec_addr);
|
||||
|
||||
vec_size_t new_length = h->size + 1;
|
||||
|
||||
// make sure there is enough room for the new element
|
||||
if (!vector_has_space(h))
|
||||
{
|
||||
h = vector_realloc(h, type_size);
|
||||
*vec_addr = h->data;
|
||||
}
|
||||
// move trailing elements
|
||||
memmove(&h->data[(pos + 1) * type_size],
|
||||
&h->data[pos * type_size],
|
||||
(h->size - pos) * type_size);
|
||||
|
||||
h->size = new_length;
|
||||
|
||||
return &h->data[pos * type_size];
|
||||
}
|
||||
|
||||
void _vector_erase(vector vec, vec_type_t type_size, vec_size_t pos, vec_size_t len)
|
||||
{
|
||||
vector_header* h = vector_get_header(vec);
|
||||
memmove(&h->data[pos * type_size],
|
||||
&h->data[(pos + len) * type_size],
|
||||
(h->size - pos - len) * type_size);
|
||||
|
||||
h->size -= len;
|
||||
}
|
||||
|
||||
void _vector_remove(vector vec, vec_type_t type_size, vec_size_t pos)
|
||||
{
|
||||
_vector_erase(vec, type_size, pos, 1);
|
||||
}
|
||||
|
||||
void vector_pop(vector vec) { --vector_get_header(vec)->size; }
|
||||
|
||||
void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t capacity)
|
||||
{
|
||||
vector_header* h = vector_get_header(*vec_addr);
|
||||
if (h->capacity >= capacity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
h = (vector_header*)realloc(h, sizeof(vector_header) + capacity * type_size);
|
||||
h->capacity = capacity;
|
||||
*vec_addr = &h->data;
|
||||
}
|
||||
|
||||
vector _vector_copy(vector vec, vec_type_t type_size)
|
||||
{
|
||||
vector_header* h = vector_get_header(vec);
|
||||
size_t alloc_size = sizeof(vector_header) + h->size * type_size;
|
||||
vector_header* copy_h = (vector_header*)malloc(alloc_size);
|
||||
memcpy(copy_h, h, alloc_size);
|
||||
copy_h->capacity = copy_h->size;
|
||||
|
||||
return ©_h->data;
|
||||
}
|
||||
127
src/vec.h
Normal file
127
src/vec.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2024, Mashpoe
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef vec_h
|
||||
#define vec_h
|
||||
|
||||
#ifdef __cpp_decltype
|
||||
#include <type_traits>
|
||||
#define typeof(T) std::remove_reference<std::add_lvalue_reference<decltype(T)>::type>::type
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// generic type for internal use
|
||||
typedef void* vector;
|
||||
// number of elements in a vector
|
||||
typedef size_t vec_size_t;
|
||||
// number of bytes for a type
|
||||
typedef size_t vec_type_t;
|
||||
|
||||
// TODO: more rigorous check for typeof support with different compilers
|
||||
#if _MSC_VER == 0 || __STDC_VERSION__ >= 202311L || defined __cpp_decltype
|
||||
|
||||
// shortcut defines
|
||||
|
||||
// vec_addr is a vector* (aka type**)
|
||||
#define vector_add_dst(vec_addr)\
|
||||
((typeof(*vec_addr))(\
|
||||
_vector_add_dst((vector*)vec_addr, sizeof(**vec_addr))\
|
||||
))
|
||||
#define vector_insert_dst(vec_addr, pos)\
|
||||
((typeof(*vec_addr))(\
|
||||
_vector_insert_dst((vector*)vec_addr, sizeof(**vec_addr), pos)))
|
||||
|
||||
#define vector_add(vec_addr, value)\
|
||||
(*vector_add_dst(vec_addr) = value)
|
||||
#define vector_insert(vec_addr, pos, value)\
|
||||
(*vector_insert_dst(vec_addr, pos) = value)
|
||||
|
||||
#else
|
||||
|
||||
#define vector_add_dst(vec_addr, type)\
|
||||
((type*)_vector_add_dst((vector*)vec_addr, sizeof(type)))
|
||||
#define vector_insert_dst(vec_addr, type, pos)\
|
||||
((type*)_vector_insert_dst((vector*)vec_addr, sizeof(type), pos))
|
||||
|
||||
#define vector_add(vec_addr, type, value)\
|
||||
(*vector_add_dst(vec_addr, type) = value)
|
||||
#define vector_insert(vec_addr, type, pos, value)\
|
||||
(*vector_insert_dst(vec_addr, type, pos) = value)
|
||||
|
||||
#endif
|
||||
|
||||
// vec is a vector (aka type*)
|
||||
#define vector_erase(vec, pos, len)\
|
||||
(_vector_erase((vector)vec, sizeof(*vec), pos, len))
|
||||
#define vector_remove(vec, pos)\
|
||||
(_vector_remove((vector)vec, sizeof(*vec), pos))
|
||||
|
||||
#define vector_reserve(vec_addr, capacity)\
|
||||
(_vector_reserve((vector*)vec_addr, sizeof(**vec_addr), capacity))
|
||||
|
||||
#define vector_copy(vec)\
|
||||
(_vector_copy((vector)vec, sizeof(*vec)))
|
||||
|
||||
vector vector_create(void);
|
||||
|
||||
void vector_free(vector vec);
|
||||
|
||||
void* _vector_add_dst(vector* vec_addr, vec_type_t type_size);
|
||||
|
||||
void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos);
|
||||
|
||||
void _vector_erase(vector vec_addr, vec_type_t type_size, vec_size_t pos, vec_size_t len);
|
||||
|
||||
void _vector_remove(vector vec_addr, vec_type_t type_size, vec_size_t pos);
|
||||
|
||||
void vector_pop(vector vec);
|
||||
|
||||
void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t capacity);
|
||||
|
||||
vector _vector_copy(vector vec, vec_type_t type_size);
|
||||
|
||||
vec_size_t vector_size(vector vec);
|
||||
|
||||
vec_size_t vector_capacity(vector vec);
|
||||
|
||||
// closing bracket for extern "C"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* vec_h */
|
||||
Reference in New Issue
Block a user