• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ArkScript-lang / Ark / 14012558627

22 Mar 2025 09:33PM UTC coverage: 79.378% (+0.5%) from 78.852%
14012558627

push

github

SuperFola
chore: cleaning up dead code and old todos

6 of 14 new or added lines in 5 files covered. (42.86%)

248 existing lines in 6 files now uncovered.

6047 of 7618 relevant lines covered (79.38%)

77956.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

43.51
/src/arkreactor/Compiler/BytecodeReader.cpp
1
#include <Ark/Compiler/BytecodeReader.hpp>
2

3
#include <Ark/Compiler/Instructions.hpp>
4
#include <Ark/Builtins/Builtins.hpp>
5

6
#include <iomanip>
7
#include <unordered_map>
8
#include <picosha2.h>
9
#include <Ark/Compiler/Serialization/IEEE754Serializer.hpp>
10
#include <Ark/Compiler/Serialization/IntegerSerializer.hpp>
11
#include <fmt/core.h>
12
#include <fmt/color.h>
13

14
namespace Ark
15
{
16
    using namespace Ark::internal;
17

18
    void BytecodeReader::feed(const bytecode_t& bytecode)
254✔
19
    {
254✔
20
        m_bytecode = bytecode;
254✔
21
    }
254✔
22

23
    void BytecodeReader::feed(const std::string& file)
×
24
    {
×
25
        std::ifstream ifs(file, std::ios::binary | std::ios::ate);
×
26
        if (!ifs.good())
×
27
            throw std::runtime_error(fmt::format("[BytecodeReader] Couldn't open file '{}'", file));
×
28

29
        const auto pos = ifs.tellg();
×
30
        // reserve appropriate number of bytes
31
        std::vector<char> temp(static_cast<std::size_t>(pos));
×
32
        ifs.seekg(0, std::ios::beg);
×
33
        ifs.read(&temp[0], pos);
×
34
        ifs.close();
×
35

36
        m_bytecode = bytecode_t(static_cast<std::size_t>(pos));
×
37
        for (std::size_t i = 0; i < static_cast<std::size_t>(pos); ++i)
×
38
            m_bytecode[i] = static_cast<uint8_t>(temp[i]);
×
39
    }
×
40

41
    bool BytecodeReader::checkMagic() const
669✔
42
    {
669✔
43
        return m_bytecode.size() >= bytecode::Magic.size() &&
1,337✔
44
            m_bytecode[0] == bytecode::Magic[0] &&
668✔
45
            m_bytecode[1] == bytecode::Magic[1] &&
498✔
46
            m_bytecode[2] == bytecode::Magic[2] &&
996✔
47
            m_bytecode[3] == bytecode::Magic[3];
498✔
48
    }
49

50
    Version BytecodeReader::version() const
83✔
51
    {
83✔
52
        if (!checkMagic() || m_bytecode.size() < bytecode::Magic.size() + bytecode::Version.size())
83✔
53
            return Version { 0, 0, 0 };
×
54

55
        return Version {
332✔
56
            .major = static_cast<uint16_t>((m_bytecode[4] << 8) + m_bytecode[5]),
83✔
57
            .minor = static_cast<uint16_t>((m_bytecode[6] << 8) + m_bytecode[7]),
83✔
58
            .patch = static_cast<uint16_t>((m_bytecode[8] << 8) + m_bytecode[9])
83✔
59
        };
60
    }
83✔
61

62
    unsigned long long BytecodeReader::timestamp() const
1✔
63
    {
1✔
64
        // 4 (ark\0) + version (2 bytes / number) + timestamp = 18 bytes
65
        if (!checkMagic() || m_bytecode.size() < bytecode::HeaderSize)
1✔
66
            return 0;
×
67

68
        // reading the timestamp in big endian
69
        using timestamp_t = unsigned long long;
70
        return (static_cast<timestamp_t>(m_bytecode[10]) << 56) +
3✔
71
            (static_cast<timestamp_t>(m_bytecode[11]) << 48) +
2✔
72
            (static_cast<timestamp_t>(m_bytecode[12]) << 40) +
2✔
73
            (static_cast<timestamp_t>(m_bytecode[13]) << 32) +
2✔
74
            (static_cast<timestamp_t>(m_bytecode[14]) << 24) +
2✔
75
            (static_cast<timestamp_t>(m_bytecode[15]) << 16) +
2✔
76
            (static_cast<timestamp_t>(m_bytecode[16]) << 8) +
2✔
77
            static_cast<timestamp_t>(m_bytecode[17]);
1✔
78
    }
1✔
79

80
    std::vector<unsigned char> BytecodeReader::sha256() const
83✔
81
    {
83✔
82
        if (!checkMagic() || m_bytecode.size() < bytecode::HeaderSize + picosha2::k_digest_size)
83✔
83
            return {};
×
84

85
        std::vector<unsigned char> sha(picosha2::k_digest_size);
83✔
86
        for (std::size_t i = 0; i < picosha2::k_digest_size; ++i)
2,739✔
87
            sha[i] = m_bytecode[bytecode::HeaderSize + i];
2,656✔
88
        return sha;
83✔
89
    }
166✔
90

91
    Symbols BytecodeReader::symbols() const
83✔
92
    {
83✔
93
        if (!checkMagic() || m_bytecode.size() < bytecode::HeaderSize + picosha2::k_digest_size ||
166✔
94
            m_bytecode[bytecode::HeaderSize + picosha2::k_digest_size] != SYM_TABLE_START)
83✔
95
            return {};
×
96

97
        std::size_t i = bytecode::HeaderSize + picosha2::k_digest_size + 1;
83✔
98
        const uint16_t size = readNumber(i);
83✔
99
        i++;
83✔
100

101
        Symbols block;
83✔
102
        block.start = bytecode::HeaderSize + picosha2::k_digest_size;
83✔
103
        block.symbols.reserve(size);
83✔
104

105
        for (uint16_t j = 0; j < size; ++j)
2,463✔
106
        {
107
            std::string content;
2,380✔
108
            while (m_bytecode[i] != 0)
24,125✔
109
                content.push_back(static_cast<char>(m_bytecode[i++]));
21,745✔
110
            i++;
2,380✔
111

112
            block.symbols.push_back(content);
2,380✔
113
        }
2,380✔
114

115
        block.end = i;
83✔
116
        return block;
83✔
117
    }
83✔
118

119
    Values BytecodeReader::values(const Symbols& symbols) const
83✔
120
    {
83✔
121
        if (!checkMagic())
83✔
122
            return {};
×
123

124
        std::size_t i = symbols.end;
83✔
125
        if (m_bytecode[i] != VAL_TABLE_START)
83✔
126
            return {};
×
127
        i++;
83✔
128

129
        const uint16_t size = readNumber(i);
83✔
130
        i++;
83✔
131
        Values block;
83✔
132
        block.start = symbols.end;
83✔
133
        block.values.reserve(size);
83✔
134

135
        for (uint16_t j = 0; j < size; ++j)
2,964✔
136
        {
137
            const uint8_t type = m_bytecode[i];
2,881✔
138
            i++;
2,881✔
139

140
            if (type == NUMBER_TYPE)
2,881✔
141
            {
142
                auto exp = deserializeLE<decltype(ieee754::DecomposedDouble::exponent)>(
1,040✔
143
                    m_bytecode.begin() + static_cast<std::vector<uint8_t>::difference_type>(i), m_bytecode.end());
520✔
144
                i += sizeof(decltype(exp));
520✔
145
                auto mant = deserializeLE<decltype(ieee754::DecomposedDouble::mantissa)>(
1,040✔
146
                    m_bytecode.begin() + static_cast<std::vector<uint8_t>::difference_type>(i), m_bytecode.end());
520✔
147
                i += sizeof(decltype(mant));
520✔
148

149
                const ieee754::DecomposedDouble d { exp, mant };
520✔
150
                double val = ieee754::deserialize(d);
520✔
151
                block.values.emplace_back(val);
520✔
152
            }
520✔
153
            else if (type == STRING_TYPE)
2,361✔
154
            {
155
                std::string val;
1,150✔
156
                while (m_bytecode[i] != 0)
20,939✔
157
                    val.push_back(static_cast<char>(m_bytecode[i++]));
19,789✔
158
                block.values.emplace_back(val);
1,150✔
159
            }
1,150✔
160
            else if (type == FUNC_TYPE)
1,211✔
161
            {
162
                const uint16_t addr = readNumber(i);
1,211✔
163
                i++;
1,211✔
164
                block.values.emplace_back(addr);
1,211✔
165
            }
1,211✔
166
            else
167
                throw std::runtime_error(fmt::format("Unknown value type: {:x}", type));
×
168
            i++;
2,881✔
169
        }
2,881✔
170

171
        block.end = i;
83✔
172
        return block;
83✔
173
    }
83✔
174

175
    Code BytecodeReader::code(const Values& values) const
83✔
176
    {
83✔
177
        if (!checkMagic())
83✔
178
            return {};
×
179

180
        std::size_t i = values.end;
83✔
181

182
        Code block;
83✔
183
        block.start = i;
83✔
184

185
        while (m_bytecode[i] == CODE_SEGMENT_START)
1,294✔
186
        {
187
            i++;
1,294✔
188
            const std::size_t size = readNumber(i) * 4;
1,294✔
189
            i++;
1,294✔
190

191
            block.pages.emplace_back().reserve(size);
1,294✔
192
            for (std::size_t j = 0; j < size; ++j)
147,194✔
193
                block.pages.back().push_back(m_bytecode[i++]);
145,900✔
194

195
            if (i == m_bytecode.size())
1,294✔
196
                break;
83✔
197
        }
1,294✔
198

199
        return block;
83✔
200
    }
83✔
201

202
    void BytecodeReader::display(const BytecodeSegment segment,
×
203
                                 const std::optional<uint16_t> sStart,
204
                                 const std::optional<uint16_t> sEnd,
205
                                 const std::optional<uint16_t> cPage) const
206
    {
×
207
        if (!checkMagic())
×
208
        {
209
            fmt::println("Invalid format");
×
210
            return;
×
211
        }
212

213
        auto [major, minor, patch] = version();
×
214
        fmt::println("Version:   {}.{}.{}", major, minor, patch);
×
215
        fmt::println("Timestamp: {}", timestamp());
×
216
        fmt::print("SHA256:    ");
×
217
        for (const auto sha = sha256(); unsigned char h : sha)
×
218
            fmt::print("{:02x}", h);
×
219
        fmt::print("\n\n");
×
220

221
        // reading the different tables, one after another
222

223
        if ((sStart.has_value() && !sEnd.has_value()) || (!sStart.has_value() && sEnd.has_value()))
×
224
        {
225
            fmt::print(fmt::fg(fmt::color::red), "Both start and end parameter need to be provided together\n");
×
226
            return;
227
        }
×
228
        if (sStart.has_value() && sEnd.has_value() && sStart.value() >= sEnd.value())
×
229
        {
230
            fmt::print(fmt::fg(fmt::color::red), "Invalid slice start and end arguments\n");
×
231
            return;
232
        }
×
233

234
        const auto syms = symbols();
×
235
        const auto vals = values(syms);
×
236
        const auto code_block = code(vals);
×
237

238
        // symbols table
239
        {
240
            std::size_t size = syms.symbols.size();
×
241
            std::size_t sliceSize = size;
×
242
            bool showSym = (segment == BytecodeSegment::All || segment == BytecodeSegment::Symbols);
×
243

244
            if (showSym && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size))
×
245
                fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size);
×
246
            else if (showSym && sStart.has_value() && sEnd.has_value())
×
247
                sliceSize = sEnd.value() - sStart.value() + 1;
×
248

249
            if (showSym || segment == BytecodeSegment::HeadersOnly)
×
250
                fmt::println("{} (length: {})", fmt::styled("Symbols table", fmt::fg(fmt::color::cyan)), sliceSize);
×
251

252
            for (std::size_t j = 0; j < size; ++j)
×
253
            {
254
                if (auto start = sStart; auto end = sEnd)
×
255
                    showSym = showSym && (j >= start.value() && j <= end.value());
×
256

257
                if (showSym)
×
258
                    fmt::println("{}) {}", j, syms.symbols[j]);
×
259
            }
×
260

261
            if (showSym)
×
262
                fmt::print("\n");
×
263
            if (segment == BytecodeSegment::Symbols)
×
264
                return;
×
265
        }
×
266

267
        // values table
268
        {
269
            std::size_t size = vals.values.size();
×
270
            std::size_t sliceSize = size;
×
271

272
            bool showVal = (segment == BytecodeSegment::All || segment == BytecodeSegment::Values);
×
273
            if (showVal && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size))
×
274
                fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size);
×
275
            else if (showVal && sStart.has_value() && sEnd.has_value())
×
276
                sliceSize = sEnd.value() - sStart.value() + 1;
×
277

278
            if (showVal || segment == BytecodeSegment::HeadersOnly)
×
279
                fmt::println("{} (length: {})", fmt::styled("Constants table", fmt::fg(fmt::color::cyan)), sliceSize);
×
280

281
            for (std::size_t j = 0; j < size; ++j)
×
282
            {
283
                if (auto start = sStart; auto end = sEnd)
×
284
                    showVal = showVal && (j >= start.value() && j <= end.value());
×
285

286
                if (showVal)
×
287
                {
288
                    switch (const auto val = vals.values[j]; val.valueType())
×
289
                    {
×
290
                        case ValueType::Number:
291
                            fmt::println("{}) (Number) {}", j, val.number());
×
292
                            break;
×
293
                        case ValueType::String:
294
                            fmt::println("{}) (String) {}", j, val.string());
×
295
                            break;
×
296
                        case ValueType::PageAddr:
297
                            fmt::println("{}) (PageAddr) {}", j, val.pageAddr());
×
298
                            break;
×
299
                        default:
300
                            fmt::print(fmt::fg(fmt::color::red), "Value type not handled: {}\n", types_to_str[static_cast<std::size_t>(val.valueType())]);
×
301
                            break;
302
                    }
×
303
                }
×
304
            }
×
305

306
            if (showVal)
×
307
                fmt::print("\n");
×
308
            if (segment == BytecodeSegment::Values)
×
309
                return;
×
310
        }
×
311

312
        const auto stringify_value = [](const Value& val) -> std::string {
×
313
            switch (val.valueType())
×
314
            {
×
315
                case ValueType::Number:
316
                    return fmt::format("{} (Number)", val.number());
×
317
                case ValueType::String:
318
                    return fmt::format("{} (String)", val.string());
×
319
                case ValueType::PageAddr:
320
                    return fmt::format("{} (PageAddr)", val.pageAddr());
×
321
                default:
322
                    return "";
×
323
            }
324
        };
×
325

326
        enum class ArgKind
327
        {
328
            Symbol,
329
            Value,
330
            Builtin,
331
            Raw
332
        };
333

334
        struct Arg
335
        {
336
            ArgKind kind;
337
            uint16_t arg;
338
        };
339

340
        const std::unordered_map<Instruction, ArgKind> arg_kinds = {
×
341
            { LOAD_SYMBOL, ArgKind::Symbol },
342
            { LOAD_SYMBOL_BY_INDEX, ArgKind::Raw },
343
            { LOAD_CONST, ArgKind::Value },
344
            { POP_JUMP_IF_TRUE, ArgKind::Raw },
345
            { STORE, ArgKind::Symbol },
346
            { SET_VAL, ArgKind::Symbol },
347
            { POP_JUMP_IF_FALSE, ArgKind::Raw },
348
            { JUMP, ArgKind::Raw },
349
            { CALL, ArgKind::Raw },
350
            { CALL_BUILTIN, ArgKind::Raw },
351
            { CAPTURE, ArgKind::Symbol },
352
            { BUILTIN, ArgKind::Builtin },
353
            { DEL, ArgKind::Symbol },
354
            { MAKE_CLOSURE, ArgKind::Value },
355
            { GET_FIELD, ArgKind::Symbol },
356
            { PLUGIN, ArgKind::Value },
357
            { LIST, ArgKind::Raw },
358
            { APPEND, ArgKind::Raw },
359
            { CONCAT, ArgKind::Raw },
360
            { APPEND_IN_PLACE, ArgKind::Raw },
361
            { CONCAT_IN_PLACE, ArgKind::Raw }
362
        };
363

364
        const auto color_print_inst = [&syms, &vals, &stringify_value](const std::string& name, std::optional<Arg> arg = std::nullopt) {
×
365
            fmt::print("{}", fmt::styled(name, fmt::fg(fmt::color::gold)));
×
UNCOV
366
            if (arg.has_value())
×
367
            {
368
                switch (auto [kind, idx] = arg.value(); kind)
×
UNCOV
369
                {
×
370
                    case ArgKind::Symbol:
371
                        fmt::print(fmt::fg(fmt::color::green), " {}\n", syms.symbols[idx]);
×
UNCOV
372
                        break;
×
373
                    case ArgKind::Value:
374
                        fmt::print(fmt::fg(fmt::color::magenta), " {}\n", stringify_value(vals.values[idx]));
×
UNCOV
375
                        break;
×
376
                    case ArgKind::Builtin:
377
                        fmt::print(" {}\n", Builtins::builtins[idx].first);
×
UNCOV
378
                        break;
×
379
                    case ArgKind::Raw:
UNCOV
380
                        fmt::print(fmt::fg(fmt::color::red), " ({})\n", idx);
×
381
                        break;
382
                }
×
UNCOV
383
            }
×
384
            else
385
                fmt::print("\n");
×
UNCOV
386
        };
×
387

UNCOV
388
        if (segment == BytecodeSegment::All || segment == BytecodeSegment::Code || segment == BytecodeSegment::HeadersOnly)
×
389
        {
UNCOV
390
            uint16_t pp = 0;
×
391

UNCOV
392
            for (const auto& page : code_block.pages)
×
393
            {
UNCOV
394
                bool displayCode = true;
×
395

396
                if (auto wanted_page = cPage)
×
UNCOV
397
                    displayCode = pp == wanted_page.value();
×
398

399
                if (displayCode)
×
400
                    fmt::println(
×
401
                        "{} {} (length: {})",
×
402
                        fmt::styled("Code segment", fmt::fg(fmt::color::magenta)),
×
403
                        fmt::styled(pp, fmt::fg(fmt::color::magenta)),
×
UNCOV
404
                        page.size());
×
405

UNCOV
406
                if (page.empty())
×
407
                {
408
                    if (displayCode)
×
409
                        fmt::print("NOP");
×
UNCOV
410
                }
×
411
                else
412
                {
413
                    if (cPage.value_or(pp) != pp)
×
414
                        continue;
×
415
                    if (segment == BytecodeSegment::HeadersOnly)
×
416
                        continue;
×
UNCOV
417
                    if (sStart.has_value() && sEnd.has_value() && ((sStart.value() > page.size()) || (sEnd.value() > page.size())))
×
418
                    {
419
                        fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", page.size());
×
UNCOV
420
                        return;
×
421
                    }
422

UNCOV
423
                    for (std::size_t j = sStart.value_or(0), end = sEnd.value_or(page.size()); j < end; j += 4)
×
424
                    {
UNCOV
425
                        const uint8_t inst = page[j];
×
426
                        // TEMP
427
                        const uint8_t padding = page[j + 1];
×
UNCOV
428
                        const auto arg = static_cast<uint16_t>((page[j + 2] << 8) + page[j + 3]);
×
429

430
                        // instruction number
UNCOV
431
                        fmt::print(fmt::fg(fmt::color::cyan), "{:>4}", j / 4);
×
432
                        // padding inst arg arg
UNCOV
433
                        fmt::print(" {:02x} {:02x} {:02x} {:02x} ", inst, padding, page[j + 2], page[j + 3]);
×
434

UNCOV
435
                        if (const auto idx = static_cast<std::size_t>(inst); idx < InstructionNames.size())
×
436
                        {
437
                            const auto inst_name = InstructionNames[idx];
×
438
                            if (const auto iinst = static_cast<Instruction>(inst); arg_kinds.contains(iinst))
×
UNCOV
439
                                color_print_inst(inst_name, Arg { arg_kinds.at(iinst), arg });
×
440
                            else
441
                                color_print_inst(inst_name);
×
UNCOV
442
                        }
×
443
                        else
444
                            fmt::println("Unknown instruction");
×
UNCOV
445
                    }
×
446
                }
447
                if (displayCode && segment != BytecodeSegment::HeadersOnly)
×
UNCOV
448
                    fmt::print("\n");
×
449

450
                ++pp;
×
451
            }
×
452
        }
×
UNCOV
453
    }
×
454

455
    uint16_t BytecodeReader::readNumber(std::size_t& i) const
2,671✔
456
    {
2,671✔
457
        const auto x = static_cast<uint16_t>(m_bytecode[i] << 8);
2,671✔
458
        const uint16_t y = m_bytecode[++i];
2,671✔
459
        return x + y;
5,342✔
460
    }
2,671✔
461
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc