@@ -22,7 +22,7 @@ export namespace CppUtils::Language::VirtualMachine
2222 return References{std::ref(variables)...};
2323 }
2424
25- template<class Functions = NoFunctions, class References = NoReferences>
25+ template<class... Types, class Functions = NoFunctions, class References = NoReferences>
2626 [[nodiscard]] inline /* constexpr */ auto execute(
2727 String::StringView auto source,
2828 const Functions& functions = NoFunctions{},
@@ -33,6 +33,7 @@ export namespace CppUtils::Language::VirtualMachine
3333 static_assert(Type::Specializes<Functions, std::tuple>);
3434 static_assert(Type::Specializes<References, std::tuple>);
3535
36+ constexpr auto types = std::make_tuple(Types{}...);
3637 constexpr auto nbFunctions = std::tuple_size_v<std::remove_cvref_t<decltype(functions)>>;
3738 constexpr auto nbReferences = std::tuple_size_v<std::remove_cvref_t<decltype(references)>>;
3839
@@ -84,21 +85,6 @@ export namespace CppUtils::Language::VirtualMachine
8485 skipComment(position);
8586 break;
8687
87- case '~':
88- if (auto identifier = stack.template pop<std::size_t>(); not identifier) [[unlikely]]
89- return std::unexpected{identifier.error()};
90- else if (identifier.value() < std::tuple_size_v<Functions>) [[unlikely]]
91- return std::unexpected{"Variable identifier too small"sv};
92- else if (identifier.value() >= std::tuple_size_v<Functions> + std::tuple_size_v<References>) [[unlikely]]
93- return std::unexpected{"Variable identifier too large"sv};
94- else if constexpr (nbReferences == 0)
95- return std::unexpected{"No reference defined"sv};
96- else if (auto size = Type::Tuple::visitAt(references, identifier.value(), [](auto& reference) { return sizeof(decltype(reference.get())); }); not size)
97- return std::unexpected{size.error()};
98- else if (auto result = stack.drop(size.value()); not result) [[unlikely]]
99- return result;
100- break;
101-
10288 case '(':
10389 lastStackPositions.push(std::size(stack));
10490 break;
@@ -138,14 +124,22 @@ export namespace CppUtils::Language::VirtualMachine
138124 return std::unexpected{result.error()};
139125 break;
140126
141- case '\' ':
127+ case '" ':
142128 if constexpr (nbReferences == 0)
143129 return std::unexpected{"No reference defined"sv};
144130 else if (auto identifier = stack.template pop<std::size_t>(); not identifier) [[unlikely]]
145131 return std::unexpected{identifier.error()};
146132 else if (identifier.value() >= nbReferences) [[unlikely]]
147133 return std::unexpected{"Reference identifier too large"sv};
148- else if (auto result = Type::Tuple::visitAt(references, identifier.value(), [&stack](auto& reference) { stack.push(reference.get()); }); not result)
134+ else if (auto result = Type::Tuple::visitAt(references, identifier.value(), [&stack](auto& reference) -> std::expected<void, std::string_view> {
135+ using ReferenceType = typename std::remove_reference_t<decltype(reference)>::type;
136+ if constexpr (not std::is_trivially_copyable_v<ReferenceType>)
137+ return std::unexpected{"Cannot copy a non-trivially copyable value"sv};
138+ else
139+ stack.push(reference.get());
140+ return {};
141+ });
142+ not result)
149143 return std::unexpected{result.error()};
150144 break;
151145
@@ -157,14 +151,19 @@ export namespace CppUtils::Language::VirtualMachine
157151 else if (referenceId.value() >= nbReferences) [[unlikely]]
158152 return std::unexpected{"Variable identifier too large"sv};
159153 else if (auto result = Type::Tuple::visitAt(references, referenceId.value(), [&stack](auto& reference) -> std::expected<void, std::string_view> {
160- if (auto result = stack.get<typename std::remove_reference_t<decltype(reference)>::type>(); not result) [[unlikely]]
161- return std::unexpected{result.error()};
162- else
163- reference.get() = std::move(result.value());
164- return {};
165- });
166- not result)
154+ using ReferenceType = typename std::remove_reference_t<decltype(reference)>::type;
155+ if constexpr (std::is_const_v<ReferenceType>)
156+ return std::unexpected{"A constant cannot be modified"sv};
157+ else if constexpr (not std::is_trivially_copyable_v<ReferenceType>)
158+ return std::unexpected{"Cannot copy a non-trivially copyable value"sv};
159+ else if (auto result = stack.get<ReferenceType>(); not result) [[unlikely]]
167160 return std::unexpected{result.error()};
161+ else
162+ reference.get() = std::move(result.value());
163+ return {};
164+ });
165+ not result)
166+ return std::unexpected{result.error()};
168167 break;
169168
170169 case '<':
@@ -185,11 +184,69 @@ export namespace CppUtils::Language::VirtualMachine
185184 return std::unexpected{"Unknown register key"sv};
186185 break;
187186
187+ case '=':
188+ if constexpr (sizeof...(Types) == 0)
189+ return std::unexpected{"No type defined"sv};
190+ else if (auto typeId = stack.template pop<std::size_t>(); not typeId) [[unlikely]]
191+ return std::unexpected{typeId.error()};
192+ else if (auto result = Type::Tuple::visitAt(types, typeId.value(), [&stack](const auto& value) -> std::expected<void, std::string_view> {
193+ using Type = std::remove_cvref_t<decltype(value)>;
194+ if (auto lhs = stack.get<Type>(sizeof(Type)); not lhs) [[unlikely]]
195+ return std::unexpected{lhs.error()};
196+ else if (auto rhs = stack.get<Type>(); not rhs) [[unlikely]]
197+ return std::unexpected{rhs.error()};
198+ else
199+ return stack.set(lhs.value() == rhs.value(), sizeof(Type) * 2);
200+ });
201+ not result) [[unlikely]]
202+ return std::unexpected{result.error()};
203+ break;
204+
205+ case '&':
206+ if (auto lhs = stack.get<bool>(sizeof(bool)); not lhs) [[unlikely]]
207+ return std::unexpected{lhs.error()};
208+ else if (auto rhs = stack.get<bool>(); not rhs) [[unlikely]]
209+ return std::unexpected{rhs.error()};
210+ else if (auto result = stack.set(lhs.value() and rhs.value(), sizeof(bool) * 2); not result) [[unlikely]]
211+ return std::unexpected{result.error()};
212+ break;
213+
214+ case '|':
215+ if (auto lhs = stack.get<bool>(sizeof(bool)); not lhs) [[unlikely]]
216+ return std::unexpected{lhs.error()};
217+ else if (auto rhs = stack.get<bool>(); not rhs) [[unlikely]]
218+ return std::unexpected{rhs.error()};
219+ else if (auto result = stack.set(lhs.value() or rhs.value(), sizeof(bool) * 2); not result) [[unlikely]]
220+ return std::unexpected{result.error()};
221+ break;
222+
223+ case ':':
224+ if constexpr (sizeof...(Types) == 0)
225+ return std::unexpected{"No type defined"sv};
226+ else if (auto typeId = stack.template pop<std::size_t>(); not typeId) [[unlikely]]
227+ return std::unexpected{typeId.error()};
228+ else if (auto result = Type::Tuple::visitAt(types, typeId.value(), [](const auto& value) { return value; });
229+ not result) [[unlikely]]
230+ return std::unexpected{result.error()};
231+ break;
232+
188233 case '_':
189- if (auto result = stack.template pop<std::size_t>(); not result) [[unlikely]]
234+ if constexpr (sizeof...(Types) == 0)
235+ return std::unexpected{"No type defined"sv};
236+ else if (auto typeId = stack.template pop<std::size_t>(); not typeId) [[unlikely]]
237+ return std::unexpected{typeId.error()};
238+ else if (auto result = Type::Tuple::visitAt(types, typeId.value(), [&stack](const auto& value) {
239+ return stack.drop(sizeof(std::remove_cvref_t<decltype(value)>));
240+ });
241+ not result) [[unlikely]]
190242 return std::unexpected{result.error()};
243+ break;
244+
245+ case '~':
246+ if (auto identifier = stack.template pop<std::size_t>(); not identifier) [[unlikely]]
247+ return std::unexpected{identifier.error()};
191248 else
192- registers.erase(result .value());
249+ registers.erase(identifier .value());
193250 break;
194251
195252 case '\\': ++position; break;
@@ -211,16 +268,6 @@ export namespace CppUtils::Language::VirtualMachine
211268 stack.drop(sizeof(std::size_t));
212269 break;
213270
214- case 'S':
215- if (auto lhs = stack.template get<std::size_t>(sizeof(std::size_t)); not lhs) [[unlikely]]
216- return std::unexpected{lhs.error()};
217- else
218- {
219- stack.set(stack.template get<std::size_t>().value(), sizeof(std::size_t));
220- stack.set(lhs.value());
221- break;
222- }
223-
224271 case 'X': return {};
225272
226273 case '+':
@@ -243,6 +290,8 @@ export namespace CppUtils::Language::VirtualMachine
243290
244291 case ',': stack.dump(); break;
245292
293+ case '\'': stack.set(source[++position]); break;
294+
246295 default:
247296 if (instruction >= '0' and instruction <= '9')
248297 {
0 commit comments