Skip to content

Commit 93ba83c

Browse files
committed
feat(tests): testing the new functionalities developped for the debugger
1 parent bacd46a commit 93ba83c

File tree

5 files changed

+144
-35
lines changed

5 files changed

+144
-35
lines changed

include/Ark/State.hpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,20 @@ namespace Ark
119119
*/
120120
void reset() noexcept;
121121

122+
/**
123+
* @brief Used by the debugger to add code to the VM at runtime
124+
*
125+
* @param pages
126+
* @param symbols
127+
* @param constants
128+
*/
129+
void extendBytecode(const std::vector<bytecode_t>& pages, const std::vector<std::string>& symbols, const std::vector<Value>& constants);
130+
131+
[[nodiscard]] inline const bytecode_t& bytecode() const noexcept
132+
{
133+
return m_bytecode;
134+
}
135+
122136
friend class VM;
123137
friend class Repl;
124138
friend class internal::Closure;
@@ -176,15 +190,6 @@ namespace Ark
176190
*/
177191
static std::size_t maxPageSize(const std::vector<bytecode_t>& pages);
178192

179-
/**
180-
* @brief Used by the debugger to add code to the VM at runtime
181-
*
182-
* @param pages
183-
* @param symbols
184-
* @param constants
185-
*/
186-
void extendBytecode(const std::vector<bytecode_t>& pages, const std::vector<std::string>& symbols, const std::vector<Value>& constants);
187-
188193
/**
189194
* @brief Get an instruction in a given page, with a given instruction pointer
190195
*

src/arkreactor/VM/Debugger.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,9 @@ namespace Ark::internal
5757
{
5858
context.ip = 0;
5959
context.pp = vm.m_state.m_pages.size();
60-
61-
// create dedicated scope
60+
// create dedicated scope, so that we won't be overwriting existing variables
6261
context.locals.emplace_back(context.scopes_storage.data(), context.locals.back().storageEnd());
6362

64-
// todo: test state.extendBytecode
6563
vm.m_state.extendBytecode(pages.value(), m_symbols, m_constants);
6664

6765
if (vm.safeRun(context) == 0)
@@ -89,8 +87,6 @@ namespace Ark::internal
8987
Welder welder(0, m_libenv, DefaultFeatures);
9088
if (!welder.computeASTFromStringWithKnownSymbols(code, m_symbols))
9189
return std::nullopt;
92-
// todo: test that we can generate bytecode using small precomputes tables and that the tables,
93-
// even if unused, are present in the resulting bytecode
9490
if (!welder.generateBytecodeUsingTables(m_symbols, m_constants, start_page_at_offset))
9591
return std::nullopt;
9692

tests/unittests/Suites/BytecodeReaderSuite.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,29 @@ using namespace Ark::literals;
1616
ut::suite<"BytecodeReader"> bcr_suite = [] {
1717
using namespace ut;
1818

19-
Ark::Welder welder(0, { lib_path });
20-
const std::string script_path = getResourcePath("BytecodeReaderSuite/ackermann.ark");
21-
22-
const auto time_start =
23-
static_cast<unsigned long long>(std::chrono::duration_cast<std::chrono::seconds>(
24-
std::chrono::system_clock::now().time_since_epoch())
25-
.count());
26-
27-
should("compile without error") = [&] {
28-
expect(mut(welder).computeASTFromFile(script_path));
29-
expect(mut(welder).generateBytecode());
30-
};
19+
"ackermann.ark"_test = [] {
20+
Ark::Welder welder(0, { lib_path });
21+
const std::string script_path = getResourcePath("BytecodeReaderSuite/ackermann.ark");
22+
23+
const auto time_start =
24+
static_cast<unsigned long long>(std::chrono::duration_cast<std::chrono::seconds>(
25+
std::chrono::system_clock::now().time_since_epoch())
26+
.count());
27+
28+
should("compile without error") = [&] {
29+
expect(mut(welder).computeASTFromFile(script_path));
30+
expect(mut(welder).generateBytecode());
31+
};
3132

32-
const auto time_end =
33-
static_cast<unsigned long long>(std::chrono::duration_cast<std::chrono::seconds>(
34-
std::chrono::system_clock::now().time_since_epoch())
35-
.count());
33+
const auto time_end =
34+
static_cast<unsigned long long>(std::chrono::duration_cast<std::chrono::seconds>(
35+
std::chrono::system_clock::now().time_since_epoch())
36+
.count());
3637

37-
Ark::BytecodeReader bcr;
38-
const auto bytecode = welder.bytecode();
39-
bcr.feed(bytecode);
38+
Ark::BytecodeReader bcr;
39+
const auto bytecode = welder.bytecode();
40+
bcr.feed(bytecode);
4041

41-
"bytecode"_test = [&] {
4242
should("find the version") = [bcr] {
4343
auto [major, minor, patch] = bcr.version();
4444
expect(that % major == ARK_VERSION_MAJOR);

tests/unittests/Suites/CompilerSuite.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ using namespace boost;
1212
ut::suite<"Compiler"> compiler_suite = [] {
1313
using namespace ut;
1414

15-
const std::vector<double> nums = { 0.11, 0.000000000011, 2, -2, 12, 6, 4, 0, 14657892.35, 3.141592653589, 4092.7984 };
15+
const std::vector<double> nums = { 0.11, 0.000000000011, 2, -2, 12, 6, 4, 0, 14657892.35, 3.141592653589, 4092.7984, -4092.7984 };
1616

1717
"IEEE754 serialization"_test = [&] {
1818
using namespace Ark::internal::ieee754;

tests/unittests/Suites/StateSuite.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <Ark/Ark.hpp>
44
#include <Ark/Compiler/Welder.hpp>
5+
#include <Ark/Compiler/BytecodeReader.hpp>
56

67
using namespace boost;
78

@@ -62,4 +63,111 @@ ut::suite<"State"> state_suite = [] {
6263
}
6364
};
6465
};
66+
67+
"[compile code with known symbols and constants]"_test = [] {
68+
Ark::Welder welder(0, {}, Ark::DefaultFeatures);
69+
const std::vector<std::string> additional_symbols = { "bar", "egg", "a", "b", "c" };
70+
const std::vector<Ark::Value> additional_constants = { Ark::Value("bar"), Ark::Value("egg") };
71+
72+
should("compile the string without any error") = [&] {
73+
expect(mut(welder).computeASTFromStringWithKnownSymbols("(let foo bar)", additional_symbols));
74+
expect(mut(welder).generateBytecodeUsingTables(additional_symbols, additional_constants, 0));
75+
};
76+
77+
const Ark::bytecode_t bytecode = welder.bytecode();
78+
Ark::State state;
79+
80+
should("accept the bytecode") = [&] {
81+
expect(nothrow([&] {
82+
mut(state).feed(bytecode, /* fail_with_exception= */ true);
83+
}));
84+
};
85+
86+
Ark::BytecodeReader bcr;
87+
bcr.feed(bytecode);
88+
const auto symbols_block = bcr.symbols();
89+
const auto values_block = bcr.values(symbols_block);
90+
91+
should("list all symbols") = [symbols_block, additional_symbols] {
92+
using namespace std::literals::string_literals;
93+
94+
std::vector<std::string> expected_symbols = additional_symbols;
95+
expected_symbols.emplace_back("foo");
96+
97+
const std::size_t symbols_bytes_count = std::accumulate(
98+
expected_symbols.begin(),
99+
expected_symbols.end(),
100+
expected_symbols.size(),
101+
[](const std::size_t acc, const std::string& sym) {
102+
return acc + sym.size();
103+
});
104+
105+
expect(that % symbols_block.symbols == expected_symbols);
106+
// 'ark\0' + version (2 bytes per number) + timestamp + sha -> first byte of the sym table
107+
expect(that % symbols_block.start == 4 + 6 + 8 + 32ull);
108+
// 50 = 4 + 6 + 8 + 32
109+
// + 1 for the header
110+
// + 2 because we need to count the size of the table (uint16)
111+
// + 3 because we need to count the \0
112+
expect(that % symbols_block.end == 50 + 1 + 2 + symbols_bytes_count);
113+
};
114+
115+
should("list all values") = [symbols_block, values_block, additional_constants] {
116+
expect(that % values_block.values.size() == additional_constants.size());
117+
expect(that % values_block.start == symbols_block.end);
118+
expect(values_block.values[0] == additional_constants[0]);
119+
expect(values_block.values[1] == additional_constants[1]);
120+
};
121+
};
122+
123+
"[extend bytecode]"_test = [] {
124+
Ark::Welder welder(0, {}, Ark::DefaultFeatures);
125+
should("compile the string without any error") = [&] {
126+
expect(mut(welder).computeASTFromString("(let foo 5) (let bar (fun (a b c) (+ a b c)))"));
127+
expect(mut(welder).generateBytecode());
128+
};
129+
130+
const Ark::bytecode_t bytecode = welder.bytecode();
131+
Ark::State state;
132+
should("accept the bytecode") = [&] {
133+
expect(nothrow([&] {
134+
mut(state).feed(bytecode, /* fail_with_exception= */ true);
135+
}));
136+
};
137+
138+
Ark::BytecodeReader bcr;
139+
bcr.feed(bytecode);
140+
const auto symbols_block = bcr.symbols();
141+
const auto values_block = bcr.values(symbols_block);
142+
143+
{
144+
Ark::Welder welder2(0, {}, Ark::DefaultFeatures);
145+
should("compute additional code") = [&] {
146+
expect(mut(welder2).computeASTFromStringWithKnownSymbols("(let x foo) (let y 10) (print (bar foo foo foo))", symbols_block.symbols));
147+
};
148+
149+
should("generate bytecode using existing bytecode tables") = [&] {
150+
// we have two existing pages in the original code
151+
expect(mut(welder2).generateBytecodeUsingTables(symbols_block.symbols, values_block.values, 2));
152+
};
153+
154+
Ark::BytecodeReader bcr2;
155+
bcr2.feed(welder2.bytecode());
156+
const auto syms = bcr2.symbols();
157+
const auto vals = bcr2.values(syms);
158+
const auto files = bcr2.filenames(vals);
159+
const auto inst_locs = bcr2.instLocations(files);
160+
const auto [pages, _] = bcr2.code(inst_locs);
161+
162+
should("have compiled a single additional page") = [&] {
163+
expect(that % pages.size() == 1u);
164+
};
165+
166+
should("extend bytecode without errors") = [&] {
167+
expect(nothrow([&] {
168+
mut(state).extendBytecode(pages, syms.symbols, vals.values);
169+
}));
170+
};
171+
}
172+
};
65173
};

0 commit comments

Comments
 (0)