|
2 | 2 |
|
3 | 3 | #include <Ark/Ark.hpp> |
4 | 4 | #include <Ark/Compiler/Welder.hpp> |
| 5 | +#include <Ark/Compiler/BytecodeReader.hpp> |
5 | 6 |
|
6 | 7 | using namespace boost; |
7 | 8 |
|
@@ -62,4 +63,111 @@ ut::suite<"State"> state_suite = [] { |
62 | 63 | } |
63 | 64 | }; |
64 | 65 | }; |
| 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 | + }; |
65 | 173 | }; |
0 commit comments