Skip to content

Commit 418e770

Browse files
committed
Language/TreeParser: Spaces
1 parent 24fdba5 commit 418e770

5 files changed

Lines changed: 174 additions & 48 deletions

File tree

modules/Container/Tree.mpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export namespace CppUtils::Container
1313
{
1414
using ValueType = T;
1515
ValueType value;
16-
std::vector<Node> nodes = {};
16+
std::vector<Node<T>> nodes = {};
1717

1818
[[nodiscard]] inline constexpr auto find(const ValueType& key) const noexcept -> auto
1919
{
@@ -34,15 +34,15 @@ export namespace CppUtils::Container
3434
return find(key) != std::cend(nodes);
3535
}
3636

37-
[[nodiscard]] inline constexpr auto operator[](const ValueType& key) -> Node&
37+
[[nodiscard]] inline constexpr auto operator[](const ValueType& key) -> Node<T>&
3838
{
3939
for (auto& node : nodes)
4040
if (key == node.value)
4141
return node;
42-
return nodes.emplace_back(Node{key});
42+
return nodes.emplace_back(Node<T>{key});
4343
}
4444

45-
[[nodiscard]] inline constexpr auto operator[](const ValueType& key) const -> const Node&
45+
[[nodiscard]] inline constexpr auto operator[](const ValueType& key) const -> const Node<T>&
4646
{
4747
const auto value = find(key);
4848
if (value == std::cend(nodes))

modules/Language/TreeParser.mpp

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,60 @@ import CppUtils.Language.VirtualMachine;
99

1010
export namespace CppUtils::Language::TreeParser
1111
{
12-
inline /* constexpr */ auto compile(String::StringView auto source) -> std::expected<Container::AST<typename decltype(source)::value_type>, std::string_view>
12+
inline /* constexpr */ auto compile(const String::StringView auto& source) -> std::expected<Container::AST<typename std::remove_cvref_t<decltype(source)>::value_type>, std::string_view>
1313
{
14-
using CharT = decltype(source)::value_type;
15-
return Container::AST<CharT>{};
14+
using namespace std::literals;
15+
namespace VM = CppUtils::Language::VirtualMachine;
16+
using StringView = std::remove_cvref_t<decltype(source)>;
17+
using CharT = StringView::value_type;
18+
19+
constexpr auto treeParser = u8R"(
20+
@
21+
22+
@{.getChar#<@} / def getChar
23+
)[0;
24+
*
25+
26+
@{.isSpace#<@} / def isSpace
27+
28+
*
29+
30+
@{.skipSpaces#<@} / def skipSpaces
31+
,
32+
*
33+
34+
@{.parseKeyword#<@} / def parseKeyword
35+
36+
*
37+
38+
@{.parseNode#<@} / def parseNode
39+
/ [ ( {.getChar#>*} getChar();
40+
{.skipSpaces#>*} / skipSpaces();
41+
{.parseKeyword#>*} / parseKeyword();
42+
*
43+
44+
@{.main#<@} / def main
45+
{.parseNode#>*} / parseNode();
46+
*
47+
48+
@{.main#>*} / main();
49+
)"sv;
50+
51+
auto getChar = [](StringView string, std::size_t pos) -> CharT {
52+
return string[pos];
53+
};
54+
auto compareChars = [](CharT lhs, CharT rhs) -> bool {
55+
return lhs == rhs;
56+
};
57+
58+
auto ast = Container::AST<CharT>{};
59+
auto sourceLength = std::size(source);
60+
auto result = VM::execute<CharT>(treeParser, VM::Functions{getChar, compareChars}, VM::makeReferences(source, sourceLength, ast));
61+
if (not result)
62+
return std::unexpected{result.error()};
63+
return ast;
1664
}
65+
1766
/*
1867
template<class CharT>
1968
inline auto compile(const std::basic_string_view<CharT> source) -> Container::AST<CharT>

modules/Language/VirtualMachine.mpp

Lines changed: 86 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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
{

tests/Language/TreeParser.mpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export namespace CppUtils::UnitTest::Language::TreeParser
1919
suite.addTest("Empty source", [&] {
2020
constexpr auto source = ""sv;
2121
auto tree = Compiler::compile(source);
22+
if (not tree)
23+
Logger::print<"error">("{}", tree.error());
2224
suite.expect(tree.has_value());
2325
Logger::print("Tree:\n{}", tree.value());
2426
auto expected = AST{
@@ -27,10 +29,24 @@ export namespace CppUtils::UnitTest::Language::TreeParser
2729
suite.expectEqual(tree.value(), expected);
2830
});
2931

32+
suite.addTest("Spaces", [&] {
33+
constexpr auto source = " "sv;
34+
auto tree = Compiler::compile(source);
35+
if (not tree)
36+
Logger::print<"error">("{}", tree.error());
37+
suite.expect(tree.has_value());
38+
Logger::print("Tree:\n{}", tree.value());
39+
auto expected = AST{
40+
Node{"root"_token},
41+
String::makeHashTable<char>("root")};
42+
suite.expectEqual(tree.value(), expected);
43+
});
3044
/*
3145
suite.addTest("Single node", [&] {
3246
constexpr auto source = "node"sv;
3347
auto tree = Compiler::compile(source);
48+
if (not tree)
49+
Logger::print<"error">("{}", tree.error());
3450
suite.expect(tree.has_value());
3551
Logger::print("Tree:\n{}", tree.value());
3652
auto expected = AST{
@@ -44,6 +60,8 @@ export namespace CppUtils::UnitTest::Language::TreeParser
4460
node
4561
)"sv;
4662
auto tree = Compiler::compile(source);
63+
if (not tree)
64+
Logger::print<"error">("{}", tree.error());
4765
Logger::print("Tree:\n{}", tree);
4866
auto expected = AST{
4967
Node{"root"_token, {Node{"node"_token}}},
@@ -54,6 +72,8 @@ export namespace CppUtils::UnitTest::Language::TreeParser
5472
suite.addTest("Multiple nodes", [&] {
5573
constexpr auto source = u"foo bar"sv;
5674
auto tree = Compiler::compile(source);
75+
if (not tree)
76+
Logger::print<"error">("{}", tree.error());
5777
Logger::print("Tree:\n{}", tree);
5878
auto expected = AST{
5979
Node{"root"_token, {Node{"foo"_token}, Node{"bar"_token}}},
@@ -66,6 +86,8 @@ export namespace CppUtils::UnitTest::Language::TreeParser
6686
Hello\ World!
6787
)"sv;
6888
auto tree = Compiler::compile(source);
89+
if (not tree)
90+
Logger::print<"error">("{}", tree.error());
6991
Logger::print("Tree:\n{}", tree);
7092
auto expected = AST{
7193
Node{"root"_token, {Node{"Hello World!"_token}}},
@@ -76,6 +98,8 @@ export namespace CppUtils::UnitTest::Language::TreeParser
7698
suite.addTest("Empty node", [&] {
7799
constexpr auto source = u"node{}"sv;
78100
auto tree = Compiler::compile(source);
101+
if (not tree)
102+
Logger::print<"error">("{}", tree.error());
79103
Logger::print("Tree:\n{}", tree);
80104
auto expected = AST{
81105
Node{"root"_token, {Node{"node"_token}}},
@@ -86,6 +110,8 @@ export namespace CppUtils::UnitTest::Language::TreeParser
86110
suite.addTest("Node with content", [&] {
87111
constexpr auto source = u"parent{child0 child1}"sv;
88112
auto tree = Compiler::compile(source);
113+
if (not tree)
114+
Logger::print<"error">("{}", tree.error());
89115
Logger::print("Tree:\n{}", tree);
90116
auto expected = AST{
91117
Node{"root"_token, {Node{"parent"_token, {Node{"child0"_token}, Node{"child1"_token}}}}},
@@ -100,6 +126,8 @@ export namespace CppUtils::UnitTest::Language::TreeParser
100126
}
101127
)"sv;
102128
auto tree = Compiler::compile(source);
129+
if (not tree)
130+
Logger::print<"error">("{}", tree.error());
103131
Logger::print("Tree:\n{}", tree);
104132
auto expected = AST{
105133
Node{"root"_token, {Node{"main"_token, {Node{"print"_token, {Node{"Hello World"_token}}}}}}},

0 commit comments

Comments
 (0)