Skip to content

Commit f1baee1

Browse files
committed
feat: test against wit-bingen tests
Signed-off-by: Gordon Smith <[email protected]>
1 parent 5e1584f commit f1baee1

31 files changed

+5522
-378
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ antlr-*.jar
1616
# Python cache files
1717
__pycache__/
1818
*.pyc
19+
20+
# Generated test stubs
21+
/test/generated_stubs/
22+
/test/test_stubs_sample/

include/cmcpp.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
#define CMCPP_HPP
33

44
#include <cmcpp/context.hpp>
5+
#include <cmcpp/monostate.hpp>
6+
#include <cmcpp/bool.hpp>
57
#include <cmcpp/integer.hpp>
68
#include <cmcpp/float.hpp>
79
#include <cmcpp/string.hpp>
810
#include <cmcpp/error_context.hpp>
911
#include <cmcpp/flags.hpp>
10-
#include <cmcpp/list.hpp>
1112
#include <cmcpp/tuple.hpp>
13+
#include <cmcpp/record.hpp>
14+
#include <cmcpp/list.hpp>
1215
#include <cmcpp/variant.hpp>
1316
#include <cmcpp/func.hpp>
1417
#include <cmcpp/lower.hpp>

include/cmcpp/bool.hpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#ifndef CMCPP_BOOL_HPP
2+
#define CMCPP_BOOL_HPP
3+
4+
#include "context.hpp"
5+
#include "integer.hpp"
6+
#include "util.hpp"
7+
8+
namespace cmcpp
9+
{
10+
// Boolean ------------------------------------------------------------------
11+
template <Boolean T>
12+
inline void store(LiftLowerContext &cx, const T &v, uint32_t ptr)
13+
{
14+
uint8_t byte = v ? 1 : 0;
15+
integer::store<uint8_t>(cx, byte, ptr);
16+
}
17+
18+
template <Boolean T>
19+
inline WasmValVector lower_flat(LiftLowerContext &cx, const T &v)
20+
{
21+
using WasmValType = WasmValTypeTrait<ValTrait<T>::flat_types[0]>::type;
22+
return {static_cast<WasmValType>(v)};
23+
}
24+
25+
template <Boolean T>
26+
inline T load(const LiftLowerContext &cx, uint32_t ptr)
27+
{
28+
return convert_int_to_bool(integer::load<uint8_t>(cx, ptr));
29+
}
30+
31+
template <Boolean T>
32+
inline T lift_flat(const LiftLowerContext &cx, const CoreValueIter &vi)
33+
{
34+
return convert_int_to_bool(vi.next<int32_t>());
35+
}
36+
}
37+
38+
#endif // CMCPP_BOOL_HPP

include/cmcpp/integer.hpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,32 +49,6 @@ namespace cmcpp
4949
}
5050
}
5151

52-
// Boolean ------------------------------------------------------------------
53-
template <Boolean T>
54-
inline void store(LiftLowerContext &cx, const T &v, uint32_t ptr)
55-
{
56-
uint8_t byte = v ? 1 : 0;
57-
integer::store<uint8_t>(cx, byte, ptr);
58-
}
59-
template <Boolean T>
60-
inline WasmValVector lower_flat(LiftLowerContext &cx, const T &v)
61-
{
62-
using WasmValType = WasmValTypeTrait<ValTrait<T>::flat_types[0]>::type;
63-
return {static_cast<WasmValType>(v)};
64-
}
65-
66-
template <Boolean T>
67-
inline T load(const LiftLowerContext &cx, uint32_t ptr)
68-
{
69-
return convert_int_to_bool(integer::load<uint8_t>(cx, ptr));
70-
}
71-
72-
template <Boolean T>
73-
inline T lift_flat(const LiftLowerContext &cx, const CoreValueIter &vi)
74-
{
75-
return convert_int_to_bool(vi.next<int32_t>());
76-
}
77-
7852
// Char ------------------------------------------------------------------
7953
template <Char T>
8054
inline void store(LiftLowerContext &cx, const T &v, uint32_t ptr)

include/cmcpp/monostate.hpp

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
#ifndef CMCPP_MONOSTATE_HPP
2+
#define CMCPP_MONOSTATE_HPP
3+
4+
#include "context.hpp"
5+
#include "traits.hpp"
6+
#include "util.hpp"
7+
8+
namespace cmcpp
9+
{
10+
// Monostate (unit type for variant cases without payload) ---------------
11+
template <typename T>
12+
requires std::is_same_v<T, std::monostate>
13+
inline void store(LiftLowerContext &cx, const T &v, uint32_t ptr)
14+
{
15+
// Monostate has no data to store (size = 0)
16+
}
17+
18+
template <typename T>
19+
requires std::is_same_v<T, std::monostate>
20+
inline T load(const LiftLowerContext &cx, uint32_t ptr)
21+
{
22+
// Monostate has no data to load (size = 0)
23+
return T{};
24+
}
25+
26+
template <typename T>
27+
requires std::is_same_v<T, std::monostate>
28+
inline WasmValVector lower_flat(LiftLowerContext &cx, const T &v)
29+
{
30+
// Monostate has no flat representation (empty vector)
31+
return {};
32+
}
33+
34+
template <typename T>
35+
requires std::is_same_v<T, std::monostate>
36+
inline T lift_flat(const LiftLowerContext &cx, const CoreValueIter &vi)
37+
{
38+
// Monostate has no data to lift
39+
return T{};
40+
}
41+
42+
// Result-specific monostates (for result<_, _> edge cases) --------------
43+
template <typename T>
44+
requires std::is_same_v<T, result_ok_monostate> || std::is_same_v<T, result_err_monostate>
45+
inline void store(LiftLowerContext &cx, const T &v, uint32_t ptr)
46+
{
47+
// Result monostates have no data to store (size = 0)
48+
}
49+
50+
template <typename T>
51+
requires std::is_same_v<T, result_ok_monostate> || std::is_same_v<T, result_err_monostate>
52+
inline T load(const LiftLowerContext &cx, uint32_t ptr)
53+
{
54+
// Result monostates have no data to load (size = 0)
55+
return T{};
56+
}
57+
58+
template <typename T>
59+
requires std::is_same_v<T, result_ok_monostate> || std::is_same_v<T, result_err_monostate>
60+
inline WasmValVector lower_flat(LiftLowerContext &cx, const T &v)
61+
{
62+
// Result monostates have no flat representation (empty vector)
63+
return {};
64+
}
65+
66+
template <typename T>
67+
requires std::is_same_v<T, result_ok_monostate> || std::is_same_v<T, result_err_monostate>
68+
inline T lift_flat(const LiftLowerContext &cx, const CoreValueIter &vi)
69+
{
70+
// Result monostates have no data to lift
71+
return T{};
72+
}
73+
74+
// Result wrappers (for result<T, T> edge cases) -------------------------
75+
template <typename T>
76+
inline void store(LiftLowerContext &cx, const result_ok_wrapper<T> &v, uint32_t ptr)
77+
{
78+
store(cx, v.value, ptr);
79+
}
80+
81+
template <typename T>
82+
inline void store(LiftLowerContext &cx, const result_err_wrapper<T> &v, uint32_t ptr)
83+
{
84+
store(cx, v.value, ptr);
85+
}
86+
87+
template <typename T>
88+
inline result_ok_wrapper<T> load(const LiftLowerContext &cx, uint32_t ptr)
89+
{
90+
return result_ok_wrapper<T>{load<T>(cx, ptr)};
91+
}
92+
93+
template <typename T>
94+
inline result_err_wrapper<T> load(const LiftLowerContext &cx, uint32_t ptr)
95+
{
96+
return result_err_wrapper<T>{load<T>(cx, ptr)};
97+
}
98+
99+
template <typename T>
100+
inline WasmValVector lower_flat(LiftLowerContext &cx, const result_ok_wrapper<T> &v)
101+
{
102+
return lower_flat(cx, v.value);
103+
}
104+
105+
template <typename T>
106+
inline WasmValVector lower_flat(LiftLowerContext &cx, const result_err_wrapper<T> &v)
107+
{
108+
return lower_flat(cx, v.value);
109+
}
110+
111+
template <typename T>
112+
inline result_ok_wrapper<T> lift_flat(const LiftLowerContext &cx, const CoreValueIter &vi)
113+
{
114+
return result_ok_wrapper<T>{lift_flat<T>(cx, vi)};
115+
}
116+
117+
template <typename T>
118+
inline result_err_wrapper<T> lift_flat(const LiftLowerContext &cx, const CoreValueIter &vi)
119+
{
120+
return result_err_wrapper<T>{lift_flat<T>(cx, vi)};
121+
}
122+
}
123+
124+
// std::tuple_size and std::tuple_element specializations for result wrappers
125+
// These are needed for std::apply to work with result_ok_wrapper/result_err_wrapper
126+
// The wrappers act as single-element tuples containing their wrapped value
127+
namespace std
128+
{
129+
template <typename T>
130+
struct tuple_size<cmcpp::result_ok_wrapper<T>> : std::integral_constant<std::size_t, std::tuple_size_v<T>>
131+
{
132+
};
133+
134+
template <std::size_t I, typename T>
135+
struct tuple_element<I, cmcpp::result_ok_wrapper<T>>
136+
{
137+
using type = std::tuple_element_t<I, T>;
138+
};
139+
140+
template <typename T>
141+
struct tuple_size<cmcpp::result_err_wrapper<T>> : std::integral_constant<std::size_t, std::tuple_size_v<T>>
142+
{
143+
};
144+
145+
template <std::size_t I, typename T>
146+
struct tuple_element<I, cmcpp::result_err_wrapper<T>>
147+
{
148+
using type = std::tuple_element_t<I, T>;
149+
};
150+
}
151+
152+
// std::get specializations for result wrappers to support structured bindings and std::apply
153+
// Forward get<I> calls to the wrapped tuple
154+
namespace std
155+
{
156+
template <std::size_t I, typename T>
157+
constexpr decltype(auto) get(cmcpp::result_ok_wrapper<T> &wrapper) noexcept
158+
{
159+
return std::get<I>(wrapper.value);
160+
}
161+
162+
template <std::size_t I, typename T>
163+
constexpr decltype(auto) get(const cmcpp::result_ok_wrapper<T> &wrapper) noexcept
164+
{
165+
return std::get<I>(wrapper.value);
166+
}
167+
168+
template <std::size_t I, typename T>
169+
constexpr decltype(auto) get(cmcpp::result_ok_wrapper<T> &&wrapper) noexcept
170+
{
171+
return std::get<I>(std::move(wrapper.value));
172+
}
173+
174+
template <std::size_t I, typename T>
175+
constexpr decltype(auto) get(const cmcpp::result_ok_wrapper<T> &&wrapper) noexcept
176+
{
177+
return std::get<I>(std::move(wrapper.value));
178+
}
179+
180+
template <std::size_t I, typename T>
181+
constexpr decltype(auto) get(cmcpp::result_err_wrapper<T> &wrapper) noexcept
182+
{
183+
return std::get<I>(wrapper.value);
184+
}
185+
186+
template <std::size_t I, typename T>
187+
constexpr decltype(auto) get(const cmcpp::result_err_wrapper<T> &wrapper) noexcept
188+
{
189+
return std::get<I>(wrapper.value);
190+
}
191+
192+
template <std::size_t I, typename T>
193+
constexpr decltype(auto) get(cmcpp::result_err_wrapper<T> &&wrapper) noexcept
194+
{
195+
return std::get<I>(std::move(wrapper.value));
196+
}
197+
198+
template <std::size_t I, typename T>
199+
constexpr decltype(auto) get(const cmcpp::result_err_wrapper<T> &&wrapper) noexcept
200+
{
201+
return std::get<I>(std::move(wrapper.value));
202+
}
203+
}
204+
205+
#endif // CMCPP_MONOSTATE_HPP

include/cmcpp/record.hpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#ifndef CMCPP_RECORD_HPP
2+
#define CMCPP_RECORD_HPP
3+
4+
#include "context.hpp"
5+
#include "store.hpp"
6+
#include "load.hpp"
7+
#include "tuple.hpp"
8+
#include "util.hpp"
9+
#include <boost/pfr.hpp>
10+
11+
namespace cmcpp
12+
{
13+
// Helper to convert tuple to struct (works with plain structs, not just record_t)
14+
template <Struct S, Tuple T, std::size_t... I>
15+
S tuple_to_struct_impl(const T &t, std::index_sequence<I...>)
16+
{
17+
return S{std::get<I>(t)...};
18+
}
19+
20+
template <Struct S, Tuple T>
21+
S tuple_to_struct(const T &t)
22+
{
23+
return tuple_to_struct_impl<S>(t, std::make_index_sequence<std::tuple_size_v<T>>{});
24+
}
25+
26+
// Store a record to WebAssembly linear memory
27+
// Records are stored as tuples of their fields using Boost PFR for reflection
28+
template <Record T>
29+
inline void store(LiftLowerContext &cx, const T &v, uint32_t ptr)
30+
{
31+
// record_t<R> inherits from R, so we need to work with the base struct
32+
using base_type = typename ValTrait<T>::inner_type;
33+
const base_type &base = static_cast<const base_type &>(v);
34+
35+
// Convert the base struct to a tuple using Boost PFR reflection
36+
auto tuple_value = boost::pfr::structure_to_tuple(base);
37+
38+
// Store the tuple (which handles all fields sequentially)
39+
tuple::store(cx, tuple_value, ptr);
40+
}
41+
42+
// Load a record from WebAssembly linear memory
43+
// Records are loaded as tuples of their fields using Boost PFR for reflection
44+
template <Record T>
45+
inline T load(const LiftLowerContext &cx, uint32_t ptr)
46+
{
47+
// Get the tuple type for this record
48+
using tuple_type = typename ValTrait<T>::tuple_type;
49+
50+
// Load as a tuple
51+
auto tuple_value = tuple::load<tuple_type>(cx, ptr);
52+
53+
// Convert tuple back to the base struct
54+
using base_type = typename ValTrait<T>::inner_type;
55+
base_type base = tuple_to_struct<base_type>(tuple_value);
56+
57+
// Construct the record_t wrapper from the base
58+
T result;
59+
static_cast<base_type &>(result) = base;
60+
return result;
61+
}
62+
63+
} // namespace cmcpp
64+
65+
#endif // CMCPP_RECORD_HPP

0 commit comments

Comments
 (0)