ArkScript
A small, lisp-inspired, functional scripting language
BytecodeReader.cpp
Go to the documentation of this file.
2
5
6#include <unordered_map>
7#include <Proxy/Picosha2.hpp>
10#include <fmt/core.h>
11#include <fmt/color.h>
12
13namespace Ark
14{
15 using namespace Ark::internal;
16
17 void BytecodeReader::feed(const bytecode_t& bytecode)
18 {
19 m_bytecode = bytecode;
20 }
21
22 void BytecodeReader::feed(const std::string& file)
23 {
24 std::ifstream ifs(file, std::ios::binary | std::ios::ate);
25 if (!ifs.good())
26 throw std::runtime_error(fmt::format("[BytecodeReader] Couldn't open file '{}'", file));
27
28 const auto pos = ifs.tellg();
29 // reserve appropriate number of bytes
30 std::vector<char> temp(static_cast<std::size_t>(pos));
31 ifs.seekg(0, std::ios::beg);
32 ifs.read(&temp[0], pos);
33 ifs.close();
34
35 m_bytecode = bytecode_t(static_cast<std::size_t>(pos));
36 for (std::size_t i = 0; i < static_cast<std::size_t>(pos); ++i)
37 m_bytecode[i] = static_cast<uint8_t>(temp[i]);
38 }
39
41 {
42 return m_bytecode.size() >= bytecode::Magic.size() &&
43 m_bytecode[0] == bytecode::Magic[0] &&
44 m_bytecode[1] == bytecode::Magic[1] &&
45 m_bytecode[2] == bytecode::Magic[2] &&
47 }
48
50 {
51 if (!checkMagic() || m_bytecode.size() < bytecode::Magic.size() + bytecode::Version.size())
52 return Version { 0, 0, 0 };
53
54 return Version {
55 .major = static_cast<uint16_t>((m_bytecode[4] << 8) + m_bytecode[5]),
56 .minor = static_cast<uint16_t>((m_bytecode[6] << 8) + m_bytecode[7]),
57 .patch = static_cast<uint16_t>((m_bytecode[8] << 8) + m_bytecode[9])
58 };
59 }
60
61 unsigned long long BytecodeReader::timestamp() const
62 {
63 // 4 (ark\0) + version (2 bytes / number) + timestamp = 18 bytes
65 return 0;
66
67 // reading the timestamp in big endian
68 using timestamp_t = unsigned long long;
69 return (static_cast<timestamp_t>(m_bytecode[10]) << 56) +
70 (static_cast<timestamp_t>(m_bytecode[11]) << 48) +
71 (static_cast<timestamp_t>(m_bytecode[12]) << 40) +
72 (static_cast<timestamp_t>(m_bytecode[13]) << 32) +
73 (static_cast<timestamp_t>(m_bytecode[14]) << 24) +
74 (static_cast<timestamp_t>(m_bytecode[15]) << 16) +
75 (static_cast<timestamp_t>(m_bytecode[16]) << 8) +
76 static_cast<timestamp_t>(m_bytecode[17]);
77 }
78
79 std::vector<unsigned char> BytecodeReader::sha256() const
80 {
81 if (!checkMagic() || m_bytecode.size() < bytecode::HeaderSize + picosha2::k_digest_size)
82 return {};
83
84 std::vector<unsigned char> sha(picosha2::k_digest_size);
85 for (std::size_t i = 0; i < picosha2::k_digest_size; ++i)
86 sha[i] = m_bytecode[bytecode::HeaderSize + i];
87 return sha;
88 }
89
91 {
92 if (!checkMagic() || m_bytecode.size() < bytecode::HeaderSize + picosha2::k_digest_size ||
93 m_bytecode[bytecode::HeaderSize + picosha2::k_digest_size] != SYM_TABLE_START)
94 return {};
95
96 std::size_t i = bytecode::HeaderSize + picosha2::k_digest_size + 1;
97 const uint16_t size = readNumber(i);
98 i++;
99
100 Symbols block;
101 block.start = bytecode::HeaderSize + picosha2::k_digest_size;
102 block.symbols.reserve(size);
103
104 for (uint16_t j = 0; j < size; ++j)
105 {
106 std::string content;
107 while (m_bytecode[i] != 0)
108 content.push_back(static_cast<char>(m_bytecode[i++]));
109 i++;
110
111 block.symbols.push_back(content);
112 }
113
114 block.end = i;
115 return block;
116 }
117
119 {
120 if (!checkMagic())
121 return {};
122
123 std::size_t i = symbols.end;
124 if (m_bytecode[i] != VAL_TABLE_START)
125 return {};
126 i++;
127
128 const uint16_t size = readNumber(i);
129 i++;
130 Values block;
131 block.start = symbols.end;
132 block.values.reserve(size);
133
134 for (uint16_t j = 0; j < size; ++j)
135 {
136 const uint8_t type = m_bytecode[i];
137 i++;
138
139 if (type == NUMBER_TYPE)
140 {
142 m_bytecode.begin() + static_cast<std::vector<uint8_t>::difference_type>(i), m_bytecode.end());
143 i += sizeof(decltype(exp));
145 m_bytecode.begin() + static_cast<std::vector<uint8_t>::difference_type>(i), m_bytecode.end());
146 i += sizeof(decltype(mant));
147
148 const ieee754::DecomposedDouble d { exp, mant };
149 double val = ieee754::deserialize(d);
150 block.values.emplace_back(val);
151 }
152 else if (type == STRING_TYPE)
153 {
154 std::string val;
155 while (m_bytecode[i] != 0)
156 val.push_back(static_cast<char>(m_bytecode[i++]));
157 block.values.emplace_back(val);
158 }
159 else if (type == FUNC_TYPE)
160 {
161 const uint16_t addr = readNumber(i);
162 i++;
163 block.values.emplace_back(addr);
164 }
165 else
166 throw std::runtime_error(fmt::format("Unknown value type: {:x}", type));
167 i++;
168 }
169
170 block.end = i;
171 return block;
172 }
173
175 {
176 if (!checkMagic())
177 return {};
178
179 std::size_t i = values.end;
181 return {};
182 i++;
183
184 const uint16_t size = readNumber(i);
185 i++;
186
187 Filenames block;
188 block.start = values.end;
189 block.filenames.reserve(size);
190
191 for (uint16_t j = 0; j < size; ++j)
192 {
193 std::string val;
194 while (m_bytecode[i] != 0)
195 val.push_back(static_cast<char>(m_bytecode[i++]));
196 block.filenames.emplace_back(val);
197 i++;
198 }
199
200 block.end = i;
201 return block;
202 }
203
205 {
206 if (!checkMagic())
207 return {};
208
209 std::size_t i = filenames.end;
211 return {};
212 i++;
213
214 const uint16_t size = readNumber(i);
215 i++;
216
217 InstLocations block;
218 block.start = filenames.end;
219 block.locations.reserve(size);
220
221 for (uint16_t j = 0; j < size; ++j)
222 {
223 auto pp = readNumber(i);
224 i++;
225
226 auto ip = readNumber(i);
227 i++;
228
229 auto file_id = readNumber(i);
230 i++;
231
232 auto line = deserializeBE<uint32_t>(
233 m_bytecode.begin() + static_cast<std::vector<uint8_t>::difference_type>(i), m_bytecode.end());
234 i += 4;
235
236 block.locations.push_back(
237 { .page_pointer = pp,
238 .inst_pointer = ip,
239 .filename_id = file_id,
240 .line = line });
241 }
242
243 block.end = i;
244 return block;
245 }
246
247 Code BytecodeReader::code(const InstLocations& instLocations) const
248 {
249 if (!checkMagic())
250 return {};
251
252 std::size_t i = instLocations.end;
253
254 Code block;
255 block.start = i;
256
257 while (m_bytecode[i] == CODE_SEGMENT_START)
258 {
259 i++;
260 const std::size_t size = readNumber(i) * 4;
261 i++;
262
263 block.pages.emplace_back().reserve(size);
264 for (std::size_t j = 0; j < size; ++j)
265 block.pages.back().push_back(m_bytecode[i++]);
266
267 if (i == m_bytecode.size())
268 break;
269 }
270
271 return block;
272 }
273
275 const std::optional<uint16_t> sStart,
276 const std::optional<uint16_t> sEnd,
277 const std::optional<uint16_t> cPage) const
278 {
279 if (!checkMagic())
280 {
281 fmt::println("Invalid format");
282 return;
283 }
284
285 auto [major, minor, patch] = version();
286 fmt::println("Version: {}.{}.{}", major, minor, patch);
287 fmt::println("Timestamp: {}", timestamp());
288 fmt::print("SHA256: ");
289 for (const auto sha = sha256(); unsigned char h : sha)
290 fmt::print("{:02x}", h);
291 fmt::print("\n\n");
292
293 // reading the different tables, one after another
294
295 if ((sStart.has_value() && !sEnd.has_value()) || (!sStart.has_value() && sEnd.has_value()))
296 {
297 fmt::print(fmt::fg(fmt::color::red), "Both start and end parameter need to be provided together\n");
298 return;
299 }
300 if (sStart.has_value() && sEnd.has_value() && sStart.value() >= sEnd.value())
301 {
302 fmt::print(fmt::fg(fmt::color::red), "Invalid slice start and end arguments\n");
303 return;
304 }
305
306 const auto syms = symbols();
307 const auto vals = values(syms);
308 const auto files = filenames(vals);
309 const auto inst_locs = instLocations(files);
310 const auto code_block = code(inst_locs);
311
312 // symbols table
313 {
314 std::size_t size = syms.symbols.size();
315 std::size_t sliceSize = size;
316 bool showSym = (segment == BytecodeSegment::All || segment == BytecodeSegment::Symbols);
317
318 if (showSym && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size))
319 fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size);
320 else if (showSym && sStart.has_value() && sEnd.has_value())
321 sliceSize = sEnd.value() - sStart.value() + 1;
322
323 if (showSym || segment == BytecodeSegment::HeadersOnly)
324 fmt::println("{} (length: {})", fmt::styled("Symbols table", fmt::fg(fmt::color::cyan)), sliceSize);
325
326 for (std::size_t j = 0; j < size; ++j)
327 {
328 if (auto start = sStart; auto end = sEnd)
329 showSym = showSym && (j >= start.value() && j <= end.value());
330
331 if (showSym)
332 fmt::println("{}) {}", j, syms.symbols[j]);
333 }
334
335 if (showSym)
336 fmt::print("\n");
337 if (segment == BytecodeSegment::Symbols)
338 return;
339 }
340
341 // values table
342 {
343 std::size_t size = vals.values.size();
344 std::size_t sliceSize = size;
345
346 bool showVal = (segment == BytecodeSegment::All || segment == BytecodeSegment::Values);
347 if (showVal && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size))
348 fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size);
349 else if (showVal && sStart.has_value() && sEnd.has_value())
350 sliceSize = sEnd.value() - sStart.value() + 1;
351
352 if (showVal || segment == BytecodeSegment::HeadersOnly)
353 fmt::println("{} (length: {})", fmt::styled("Constants table", fmt::fg(fmt::color::cyan)), sliceSize);
354
355 for (std::size_t j = 0; j < size; ++j)
356 {
357 if (auto start = sStart; auto end = sEnd)
358 showVal = showVal && (j >= start.value() && j <= end.value());
359
360 if (showVal)
361 {
362 switch (const auto val = vals.values[j]; val.valueType())
363 {
365 fmt::println("{}) (Number) {}", j, val.number());
366 break;
368 fmt::println("{}) (String) {}", j, val.string());
369 break;
371 fmt::println("{}) (PageAddr) {}", j, val.pageAddr());
372 break;
373 default:
374 fmt::print(fmt::fg(fmt::color::red), "Value type not handled: {}\n", std::to_string(val.valueType()));
375 break;
376 }
377 }
378 }
379
380 if (showVal)
381 fmt::print("\n");
382 if (segment == BytecodeSegment::Values)
383 return;
384 }
385
386 // inst locs + file
387 {
388 std::size_t size = inst_locs.locations.size();
389 std::size_t sliceSize = size;
390
391 bool showVal = (segment == BytecodeSegment::All || segment == BytecodeSegment::InstructionLocation);
392 if (showVal && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size))
393 fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size);
394 else if (showVal && sStart.has_value() && sEnd.has_value())
395 sliceSize = sEnd.value() - sStart.value() + 1;
396
397 if (showVal || segment == BytecodeSegment::HeadersOnly)
398 fmt::println("{} (length: {})", fmt::styled("Instruction locations table", fmt::fg(fmt::color::cyan)), sliceSize);
399 if (showVal && size > 0)
400 fmt::println(" PP, IP");
401
402 for (std::size_t j = 0; j < size; ++j)
403 {
404 if (auto start = sStart; auto end = sEnd)
405 showVal = showVal && (j >= start.value() && j <= end.value());
406
407 const auto& location = inst_locs.locations[j];
408 if (showVal)
409 fmt::println("{:>3},{:>3} -> {}:{}", location.page_pointer, location.inst_pointer, files.filenames[location.filename_id], location.line);
410 }
411
412 if (showVal)
413 fmt::print("\n");
414 }
415
416 const auto stringify_value = [](const Value& val) -> std::string {
417 switch (val.valueType())
418 {
420 return fmt::format("{} (Number)", val.number());
422 return fmt::format("{} (String)", val.string());
424 return fmt::format("{} (PageAddr)", val.pageAddr());
425 default:
426 return "";
427 }
428 };
429
430 enum class ArgKind
431 {
432 Symbol,
433 Constant,
434 Builtin,
435 Raw, ///< eg: Stack index, jump address, number
436 ConstConst,
437 ConstSym,
438 SymConst,
439 SymSym,
440 BuiltinRaw, ///< Builtin, number
441 ConstRaw, ///< Constant, number
442 SymRaw, ///< Symbol, number
443 RawSym, ///< Symbol index, symbol
444 RawConst, ///< Symbol index, constant
445 RawRaw ///< Symbol index, symbol index
446 };
447
448 struct Arg
449 {
450 ArgKind kind;
451 uint8_t padding;
452 uint16_t arg;
453
454 [[nodiscard]] uint16_t primary() const
455 {
456 return arg & 0x0fff;
457 }
458
459 [[nodiscard]] uint16_t secondary() const
460 {
461 return static_cast<uint16_t>((padding << 4) | (arg & 0xf000) >> 12);
462 }
463 };
464
465 const std::unordered_map<Instruction, ArgKind> arg_kinds = {
466 { LOAD_SYMBOL, ArgKind::Symbol },
467 { LOAD_SYMBOL_BY_INDEX, ArgKind::Raw },
468 { LOAD_CONST, ArgKind::Constant },
469 { POP_JUMP_IF_TRUE, ArgKind::Raw },
470 { STORE, ArgKind::Symbol },
471 { SET_VAL, ArgKind::Symbol },
472 { POP_JUMP_IF_FALSE, ArgKind::Raw },
473 { JUMP, ArgKind::Raw },
474 { CALL, ArgKind::Raw },
475 { CAPTURE, ArgKind::Symbol },
476 { RENAME_NEXT_CAPTURE, ArgKind::Symbol },
477 { BUILTIN, ArgKind::Builtin },
478 { DEL, ArgKind::Symbol },
479 { MAKE_CLOSURE, ArgKind::Constant },
480 { GET_FIELD, ArgKind::Symbol },
481 { PLUGIN, ArgKind::Constant },
482 { LIST, ArgKind::Raw },
483 { APPEND, ArgKind::Raw },
484 { CONCAT, ArgKind::Raw },
485 { APPEND_IN_PLACE, ArgKind::Raw },
486 { CONCAT_IN_PLACE, ArgKind::Raw },
487 { RESET_SCOPE_JUMP, ArgKind::Raw },
488 { GET_CURRENT_PAGE_ADDR, ArgKind::Symbol },
489 { LOAD_CONST_LOAD_CONST, ArgKind::ConstConst },
490 { LOAD_CONST_STORE, ArgKind::ConstSym },
491 { LOAD_CONST_SET_VAL, ArgKind::ConstSym },
492 { STORE_FROM, ArgKind::SymSym },
493 { STORE_FROM_INDEX, ArgKind::RawSym },
494 { SET_VAL_FROM, ArgKind::SymSym },
495 { SET_VAL_FROM_INDEX, ArgKind::RawSym },
496 { INCREMENT, ArgKind::SymRaw },
497 { INCREMENT_BY_INDEX, ArgKind::RawRaw },
498 { INCREMENT_STORE, ArgKind::RawRaw },
499 { DECREMENT, ArgKind::SymRaw },
500 { DECREMENT_BY_INDEX, ArgKind::RawRaw },
501 { DECREMENT_STORE, ArgKind::SymRaw },
502 { STORE_TAIL, ArgKind::SymSym },
503 { STORE_TAIL_BY_INDEX, ArgKind::RawSym },
504 { STORE_HEAD, ArgKind::SymSym },
505 { STORE_HEAD_BY_INDEX, ArgKind::RawSym },
506 { STORE_LIST, ArgKind::RawSym },
507 { SET_VAL_TAIL, ArgKind::SymSym },
508 { SET_VAL_TAIL_BY_INDEX, ArgKind::RawSym },
509 { SET_VAL_HEAD, ArgKind::SymSym },
510 { SET_VAL_HEAD_BY_INDEX, ArgKind::RawSym },
511 { CALL_BUILTIN, ArgKind::BuiltinRaw },
512 { CALL_BUILTIN_WITHOUT_RETURN_ADDRESS, ArgKind::BuiltinRaw },
513 { LT_CONST_JUMP_IF_FALSE, ArgKind::ConstRaw },
514 { LT_CONST_JUMP_IF_TRUE, ArgKind::ConstRaw },
515 { LT_SYM_JUMP_IF_FALSE, ArgKind::SymRaw },
516 { GT_CONST_JUMP_IF_TRUE, ArgKind::ConstRaw },
517 { GT_CONST_JUMP_IF_FALSE, ArgKind::ConstRaw },
518 { GT_SYM_JUMP_IF_FALSE, ArgKind::SymRaw },
519 { EQ_CONST_JUMP_IF_TRUE, ArgKind::ConstRaw },
520 { EQ_SYM_INDEX_JUMP_IF_TRUE, ArgKind::SymRaw },
521 { NEQ_CONST_JUMP_IF_TRUE, ArgKind::ConstRaw },
522 { NEQ_SYM_JUMP_IF_FALSE, ArgKind::SymRaw },
523 { CALL_SYMBOL, ArgKind::SymRaw },
524 { CALL_CURRENT_PAGE, ArgKind::SymRaw },
525 { GET_FIELD_FROM_SYMBOL, ArgKind::SymSym },
526 { GET_FIELD_FROM_SYMBOL_INDEX, ArgKind::RawSym },
527 { AT_SYM_SYM, ArgKind::SymSym },
528 { AT_SYM_INDEX_SYM_INDEX, ArgKind::RawRaw },
529 { AT_SYM_INDEX_CONST, ArgKind::RawConst },
530 { CHECK_TYPE_OF, ArgKind::SymConst },
531 { CHECK_TYPE_OF_BY_INDEX, ArgKind::RawConst },
532 { APPEND_IN_PLACE_SYM, ArgKind::SymRaw },
533 { APPEND_IN_PLACE_SYM_INDEX, ArgKind::RawRaw },
534 { STORE_LEN, ArgKind::RawSym },
535 { LT_LEN_SYM_JUMP_IF_FALSE, ArgKind::SymRaw }
536 };
537
538 const auto builtin_name = [](const uint16_t idx) {
539 return Builtins::builtins[idx].first;
540 };
541 const auto value_str = [&stringify_value, &vals](const uint16_t idx) {
542 return stringify_value(vals.values[idx]);
543 };
544 const auto symbol_name = [&syms](const uint16_t idx) {
545 return syms.symbols[idx];
546 };
547
548 const auto color_print_inst = [=](const std::string& name, std::optional<Arg> arg = std::nullopt) {
549 fmt::print("{}", fmt::styled(name, fmt::fg(fmt::color::gold)));
550 if (arg.has_value())
551 {
552 constexpr auto sym_color = fmt::fg(fmt::color::green);
553 constexpr auto const_color = fmt::fg(fmt::color::magenta);
554 constexpr auto raw_color = fmt::fg(fmt::color::red);
555
556 switch (auto [kind, _, idx] = arg.value(); kind)
557 {
558 case ArgKind::Symbol:
559 fmt::print(sym_color, " {}\n", symbol_name(idx));
560 break;
561 case ArgKind::Constant:
562 fmt::print(const_color, " {}\n", value_str(idx));
563 break;
564 case ArgKind::Builtin:
565 fmt::print(" {}\n", builtin_name(idx));
566 break;
567 case ArgKind::Raw:
568 fmt::print(raw_color, " ({})\n", idx);
569 break;
570 case ArgKind::ConstConst:
571 fmt::print(" {}, {}\n", fmt::styled(value_str(arg->primary()), const_color), fmt::styled(value_str(arg->secondary()), const_color));
572 break;
573 case ArgKind::ConstSym:
574 fmt::print(" {}, {}\n", fmt::styled(value_str(arg->primary()), const_color), fmt::styled(symbol_name(arg->secondary()), sym_color));
575 break;
576 case ArgKind::SymConst:
577 fmt::print(" {}, {}\n", fmt::styled(symbol_name(arg->primary()), sym_color), fmt::styled(value_str(arg->secondary()), const_color));
578 break;
579 case ArgKind::SymSym:
580 fmt::print(" {}, {}\n", fmt::styled(symbol_name(arg->primary()), sym_color), fmt::styled(symbol_name(arg->secondary()), sym_color));
581 break;
582 case ArgKind::BuiltinRaw:
583 fmt::print(" {}, {}\n", builtin_name(arg->primary()), fmt::styled(arg->secondary(), raw_color));
584 break;
585 case ArgKind::ConstRaw:
586 fmt::print(" {}, {}\n", fmt::styled(value_str(arg->primary()), const_color), fmt::styled(arg->secondary(), raw_color));
587 break;
588 case ArgKind::SymRaw:
589 fmt::print(" {}, {}\n", fmt::styled(symbol_name(arg->primary()), sym_color), fmt::styled(arg->secondary(), raw_color));
590 break;
591 case ArgKind::RawSym:
592 fmt::print(" {}, {}\n", fmt::styled(arg->primary(), raw_color), fmt::styled(symbol_name(arg->secondary()), sym_color));
593 break;
594 case ArgKind::RawConst:
595 fmt::print(" {}, {}\n", fmt::styled(arg->primary(), raw_color), fmt::styled(value_str(arg->secondary()), const_color));
596 break;
597 case ArgKind::RawRaw:
598 fmt::print(" {}, {}\n", fmt::styled(arg->primary(), raw_color), fmt::styled(arg->secondary(), raw_color));
599 break;
600 }
601 }
602 else
603 fmt::print("\n");
604 };
605
606 if (segment == BytecodeSegment::All || segment == BytecodeSegment::Code || segment == BytecodeSegment::HeadersOnly)
607 {
608 uint16_t pp = 0;
609
610 for (const auto& page : code_block.pages)
611 {
612 bool displayCode = true;
613
614 if (auto wanted_page = cPage)
615 displayCode = pp == wanted_page.value();
616
617 if (displayCode)
618 fmt::println(
619 "{} {} (length: {})",
620 fmt::styled("Code segment", fmt::fg(fmt::color::magenta)),
621 fmt::styled(pp, fmt::fg(fmt::color::magenta)),
622 page.size());
623
624 if (page.empty())
625 {
626 if (displayCode)
627 fmt::print("NOP");
628 }
629 else
630 {
631 if (cPage.value_or(pp) != pp)
632 continue;
633 if (segment == BytecodeSegment::HeadersOnly)
634 continue;
635 if (sStart.has_value() && sEnd.has_value() && ((sStart.value() > page.size()) || (sEnd.value() > page.size())))
636 {
637 fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", page.size());
638 return;
639 }
640
641 for (std::size_t j = sStart.value_or(0), end = sEnd.value_or(page.size()); j < end; j += 4)
642 {
643 const uint8_t inst = page[j];
644 // TEMP
645 const uint8_t padding = page[j + 1];
646 const auto arg = static_cast<uint16_t>((page[j + 2] << 8) + page[j + 3]);
647
648 // instruction number
649 fmt::print(fmt::fg(fmt::color::cyan), "{:>4}", j / 4);
650 // padding inst arg arg
651 fmt::print(" {:02x} {:02x} {:02x} {:02x} ", inst, padding, page[j + 2], page[j + 3]);
652
653 if (const auto idx = static_cast<std::size_t>(inst); idx < InstructionNames.size())
654 {
655 const auto inst_name = InstructionNames[idx];
656 if (const auto iinst = static_cast<Instruction>(inst); arg_kinds.contains(iinst))
657 color_print_inst(inst_name, Arg { arg_kinds.at(iinst), padding, arg });
658 else
659 color_print_inst(inst_name);
660 }
661 else
662 fmt::println("Unknown instruction");
663 }
664 }
665 if (displayCode && segment != BytecodeSegment::HeadersOnly)
666 fmt::print("\n");
667
668 ++pp;
669 }
670 }
671 }
672
673 uint16_t BytecodeReader::readNumber(std::size_t& i) const
674 {
675 const auto x = static_cast<uint16_t>(m_bytecode[i] << 8);
676 const uint16_t y = m_bytecode[++i];
677 return x + y;
678 }
679}
Host the declaration of all the ArkScript builtins.
A bytecode disassembler for ArkScript.
The different instructions used by the compiler and virtual machine.
Symbols symbols() const
unsigned long long timestamp() const
Return the read timestamp from the bytecode file.
uint16_t readNumber(std::size_t &i) const
Read a number from the bytecode, under the instruction pointer i.
Filenames filenames(const Values &values) const
InstLocations instLocations(const Filenames &filenames) const
Version version() const
Code code(const InstLocations &instLocations) const
Values values(const Symbols &symbols) const
void display(BytecodeSegment segment=BytecodeSegment::All, std::optional< uint16_t > sStart=std::nullopt, std::optional< uint16_t > sEnd=std::nullopt, std::optional< uint16_t > cPage=std::nullopt) const
Display the bytecode opcode in a human friendly way.
std::vector< unsigned char > sha256() const
void feed(const std::string &file)
Construct needed data before displaying information about a given file.
ARK_API const std::vector< std::pair< std::string, Value > > builtins
constexpr std::array Magic
Definition Common.hpp:29
constexpr std::array Version
Definition Common.hpp:30
constexpr std::size_t HeaderSize
Definition Common.hpp:39
double deserialize(const DecomposedDouble d)
@ Raw
Keep all text as is without modifying it (useful for the code formatter)
T deserializeBE(std::vector< uint8_t >::const_iterator begin, std::vector< uint8_t >::const_iterator end)
Instruction
The different bytecodes are stored here.
@ CALL_BUILTIN_WITHOUT_RETURN_ADDRESS
T deserializeLE(std::vector< uint8_t >::const_iterator begin, std::vector< uint8_t >::const_iterator end)
constexpr std::array InstructionNames
std::vector< uint8_t > bytecode_t
Definition Common.hpp:22
std::string to_string(const Ark::ValueType type) noexcept
Definition Value.hpp:257
std::vector< bytecode_t > pages
std::size_t start
Point to the CODE_SEGMENT_START byte in the bytecode.
std::size_t end
Point to the byte following the last byte of the table in the bytecode.
std::vector< std::string > filenames
std::size_t start
Point to the FILENAMES_TABLE_START byte in the bytecode.
std::size_t end
Point to the byte following the last byte of the table in the bytecode.
std::size_t start
Point to the INST_LOC_TABLE_START byte in the bytecode.
std::vector< internal::InstLoc > locations
std::vector< std::string > symbols
std::size_t end
Point to the byte following the last byte of the table in the bytecode.
std::size_t start
Point to the SYM_TABLE_START byte in the bytecode.
std::vector< Value > values
std::size_t end
Point to the byte following the last byte of the table in the bytecode.
std::size_t start
Point to the VAL_TABLE_START byte in the bytecode.