5#include <unordered_map>
7#include <fmt/ostream.h>
14 using namespace literals;
17 m_logger(
"IRCompiler", debug)
20 void IRCompiler::process(
const std::vector<IR::Block>& pages,
const std::vector<std::string>& symbols,
const std::vector<ValTableElem>& values)
42 constexpr std::size_t header_size = 18;
45 std::vector<unsigned char> hash_out(picosha2::k_digest_size);
54 std::size_t index = 0;
55 for (
const auto& block :
m_ir)
57 fmt::println(stream,
"page_{}", index);
58 for (
const auto entity : block)
60 switch (entity.kind())
63 fmt::println(stream,
".L{}:", entity.label());
67 fmt::println(stream,
"\tGOTO L{}", entity.label());
71 fmt::println(stream,
"\tGOTO_IF_TRUE L{}", entity.label());
75 fmt::println(stream,
"\tGOTO_IF_FALSE L{}", entity.label());
79 fmt::println(stream,
"\t{} {}",
InstructionNames[entity.inst()], entity.primaryArg());
83 fmt::println(stream,
"\t{} {}, {}",
InstructionNames[entity.inst()], entity.primaryArg(), entity.secondaryArg());
88 fmt::println(stream,
"");
101 for (std::size_t i = 0, end =
m_ir.size(); i < end; ++i)
106 page.emplace_back(
HALT);
109 const auto page_size = std::ranges::count_if(page, [](
const auto& a) {
112 if (std::cmp_greater(page_size, std::numeric_limits<uint16_t>::max()))
113 throw std::overflow_error(fmt::format(
"Size of page {} exceeds the maximum size of 2^16 - 1", i));
116 m_bytecode.push_back(
static_cast<uint8_t
>((page_size & 0xff00) >> 8));
117 m_bytecode.push_back(
static_cast<uint8_t
>(page_size & 0x00ff));
121 std::unordered_map<IR::label_t, uint16_t> label_to_position;
122 for (
auto inst : page)
127 label_to_position[inst.label()] = pos;
135 for (
auto inst : page)
190 m_bytecode.push_back(
static_cast<uint8_t
>((n & 0xff00) >> 8));
191 m_bytecode.push_back(
static_cast<uint8_t
>(n & 0x00ff));
195 const long long timestamp = std::chrono::duration_cast<std::chrono::seconds>(
196 std::chrono::system_clock::now().time_since_epoch())
198 for (
long i = 0; i < 8; ++i)
200 const long shift = 8 * (7 - i);
201 const auto ts_byte =
static_cast<uint8_t
>((timestamp & (0xffLL << shift)) >> shift);
208 const std::size_t symbol_size = symbols.size();
209 if (symbol_size > std::numeric_limits<uint16_t>::max())
210 throw std::overflow_error(fmt::format(
"Too many symbols: {}, exceeds the maximum size of 2^16 - 1", symbol_size));
213 m_bytecode.push_back(
static_cast<uint8_t
>((symbol_size & 0xff00) >> 8));
214 m_bytecode.push_back(
static_cast<uint8_t
>(symbol_size & 0x00ff));
216 for (
const auto& sym : symbols)
219 std::ranges::transform(sym, std::back_inserter(
m_bytecode), [](
const char i) {
220 return static_cast<uint8_t
>(i);
225 const std::size_t value_size = values.size();
226 if (value_size > std::numeric_limits<uint16_t>::max())
227 throw std::overflow_error(fmt::format(
"Too many values: {}, exceeds the maximum size of 2^16 - 1", value_size));
230 m_bytecode.push_back(
static_cast<uint8_t
>((value_size & 0xff00) >> 8));
231 m_bytecode.push_back(
static_cast<uint8_t
>(value_size & 0x00ff));
240 const auto n = std::get<double>(val.value);
241 std::string t = std::to_string(n);
242 std::ranges::transform(t, std::back_inserter(
m_bytecode), [](
const char i) {
243 return static_cast<uint8_t
>(i);
251 auto t = std::get<std::string>(val.value);
252 std::ranges::transform(t, std::back_inserter(
m_bytecode), [](
const char i) {
253 return static_cast<uint8_t
>(i);
261 const std::size_t addr = std::get<std::size_t>(val.value);
262 m_bytecode.push_back(
static_cast<uint8_t
>((addr & 0xff00) >> 8));
263 m_bytecode.push_back(
static_cast<uint8_t
>(addr & 0x00ff));
Constants used by ArkScript.
constexpr int ARK_VERSION_MAJOR
constexpr int ARK_VERSION_PATCH
constexpr int ARK_VERSION_MINOR
Compile the intermediate representation to bytecode.
User defined literals for Ark internals.
IRCompiler(unsigned debug)
Create a new IRCompiler.
void dumpToStream(std::ostream &stream) const
Dump the IR given to process to an output stream.
const bytecode_t & bytecode() const noexcept
Return the constructed bytecode object.
void pushWord(const Word &word)
Push a word to the m_bytecode.
std::vector< IR::Block > m_ir
void pushFileHeader() noexcept
Push the file headers (magic, version used, timestamp)
void process(const std::vector< IR::Block > &pages, const std::vector< std::string > &symbols, const std::vector< ValTableElem > &values)
Turn a given IR into bytecode.
void pushSymAndValTables(const std::vector< std::string > &symbols, const std::vector< ValTableElem > &values)
Push the symbols and values tables.
void traceStart(std::string &&trace_name)
std::vector< Entity > Block
constexpr std::array InstructionNames
std::vector< uint8_t > bytecode_t
A Compiler Value class helper to handle multiple types.
uint8_t opcode
Instruction opcode.