19 using namespace literals;
22 m_debug(debug), m_logger(
"Compiler", debug)
33 Page { .index = 0, .is_temp =
false },
65 [&name](
const std::pair<std::string, Value>& element) ->
bool {
66 return name == element.first;
94 case NOT: [[fallthrough]];
95 case LEN: [[fallthrough]];
96 case EMPTY: [[fallthrough]];
97 case TAIL: [[fallthrough]];
98 case HEAD: [[fallthrough]];
99 case ISNIL: [[fallthrough]];
100 case TO_NUM: [[fallthrough]];
101 case TO_STR: [[fallthrough]];
152 if (!is_result_unused)
165 if (!is_result_unused)
167 static const std::optional<uint16_t> nil =
getBuiltin(
"nil");
180 compileIf(x, p, is_result_unused, is_terminal, var_name);
197 for (std::size_t i = 1, size = x.
constList().size(); i < size; ++i)
202 (i != size - 1) || is_result_unused,
204 is_terminal && (i == size - 1),
226 handleCalls(x, p, is_result_unused, is_terminal, var_name);
231 "NodeType `{}' not handled in Compiler::compileExpression. Please fill an issue on GitHub: https://github.com/ArkScript-lang/Ark",
238 const std::string& name = x.
string();
247 if (is_result_unused)
256 std::string name = c0.
string();
260 const auto argc = x.
constList().size() - 1u;
262 if (argc < 2 &&
APPEND <= inst && inst <=
POP)
263 throwCompilerError(fmt::format(
"Can not use {} with less than 2 arguments", name), c0);
264 if (inst <=
POP && std::cmp_greater(argc, std::numeric_limits<uint16_t>::max()))
267 throwCompilerError(fmt::format(
"Expected 3 arguments (list, index, value) for {}, got {}", name, argc), c0);
269 throwCompilerError(fmt::format(
"Expected 4 arguments (list, y, x, value) for {}, got {}", name, argc), c0);
272 for (std::size_t i = x.
constList().size() - 1u; i > 0; --i)
282 std::size_t inst_argc = 0;
293 inst_argc = argc - 1;
304 page(p).emplace_back(inst,
static_cast<uint16_t
>(inst_argc));
331 page(p).emplace_back(label_then);
335 page(p).emplace_back(label_end);
343 throwCompilerError(
"Invalid node ; if it was computed by a macro, check that a node is returned", x);
346 bool is_closure =
false;
347 for (
const auto& node : x.
constList()[1].constList())
358 const auto function_body_page =
Page { .index =
m_code_pages.size() - 1, .is_temp =
false };
363 for (
const auto& node : x.
constList()[1].constList())
373 page(function_body_page).emplace_back(
RET);
376 if (is_result_unused)
388 throwCompilerError(
"Invalid node ; if it was computed by a macro, check that a node is returned", x);
390 const std::string name = x.
constList()[1].string();
395 for (std::size_t idx = 2, end = x.
constList().size(); idx < end; ++idx)
407 throwCompilerError(
"Invalid node ; if it was computed by a macro, check that a node is returned", x);
413 page(p).emplace_back(label_loop);
426 page(p).emplace_back(label_end);
435 for (std::size_t i = 0, end = package_node.
constList().size(); i < end; ++i)
437 path += package_node.
constList()[i].string();
451 constexpr std::size_t start_index = 1;
456 enum class ShortcircuitOp
461 const std::optional<ShortcircuitOp> maybe_shortcircuit =
464 ? std::make_optional(ShortcircuitOp::And)
466 ? std::make_optional(ShortcircuitOp::Or)
470 if (maybe_shortcircuit.has_value())
476 "Expected at least 2 arguments while compiling '{}', got {}",
485 for (std::size_t i = 2, end = x.
constList().size(); i < end; ++i)
487 switch (maybe_shortcircuit.value())
489 case ShortcircuitOp::And:
492 case ShortcircuitOp::Or:
503 page(p).emplace_back(label_shortcircuit);
505 else if (!maybe_operator.has_value())
510 for (std::size_t i = x.
constList().size() - 1; i >= start_index; --i)
515 throwCompilerError(fmt::format(
"Invalid node inside tail call to `{}'", node.repr()), x);
525 const auto proc_page =
Page { .index =
m_temp_pages.size() - 1u, .is_temp =
true };
532 for (
auto exp = x.
constList().begin() + start_index, exp_end = x.
constList().end(); exp != exp_end; ++exp)
541 page(p).push_back(inst);
545 std::size_t args_count = 0;
546 for (
auto it = x.
constList().begin() + 1, it_end = x.
constList().end(); it != it_end; ++it)
552 page(p).emplace_back(
CALL, args_count);
558 auto op = maybe_operator.value();
561 is_result_unused =
false;
564 std::size_t exp_count = 0;
565 for (std::size_t index = start_index, size = x.
constList().size(); index < size; ++index)
570 throwCompilerError(fmt::format(
"Invalid node inside call to operator `{}'", node.repr()), x);
578 page(p).emplace_back(op);
585 page(p).emplace_back(op);
591 page(p).emplace_back(op);
593 else if (exp_count <= 1)
602 case ADD: [[fallthrough]];
603 case SUB: [[fallthrough]];
604 case MUL: [[fallthrough]];
605 case DIV: [[fallthrough]];
606 case MOD: [[fallthrough]];
613 "`{}' requires 2 arguments, but got {}.",
621 if (is_result_unused)
632 it =
m_symbols.begin() +
static_cast<std::vector<std::string>::difference_type
>(
m_symbols.size() - 1);
635 const auto distance = std::distance(
m_symbols.begin(), it);
636 if (distance < std::numeric_limits<uint16_t>::max())
637 return static_cast<uint16_t
>(distance);
644 auto it = std::ranges::find(
m_values, v);
648 it =
m_values.begin() +
static_cast<std::vector<ValTableElem>::difference_type
>(
m_values.size() - 1);
651 const auto distance = std::distance(
m_values.begin(), it);
652 if (distance < std::numeric_limits<uint16_t>::max())
653 return static_cast<uint16_t
>(distance);
660 auto it = std::ranges::find(
m_values, v);
664 it =
m_values.begin() +
static_cast<std::vector<ValTableElem>::difference_type
>(
m_values.size() - 1);
667 const auto distance = std::distance(
m_values.begin(), it);
668 if (distance < std::numeric_limits<uint16_t>::max())
669 return static_cast<uint16_t
>(distance);
670 throwCompilerError(
"Too many values (exceeds 65'536), aborting compilation.", current);
Lots of utilities about string, filesystem and more.
Host the declaration of all the ArkScript builtins.
ArkScript compiler is in charge of transforming the AST into bytecode.
Constants used by ArkScript.
User defined literals for Ark internals.
Handles the macros and their expansion in ArkScript source code.
static void compilerWarning(const std::string &message, const Node &node)
Display a warning message.
uint16_t addValue(const Node &x)
Register a given node in the value table.
std::vector< IR::Block > m_code_pages
std::vector< IR::Block > m_temp_pages
we need temporary code pages for some compilations passes
void compileExpression(const Node &x, Page p, bool is_result_unused, bool is_terminal, const std::string &var_name="")
Compile an expression (a node) recursively.
Compiler(unsigned debug)
Construct a new Compiler object.
static void throwCompilerError(const std::string &message, const Node &node)
Throw a nice error message.
void handleCalls(const Node &x, Page p, bool is_result_unused, bool is_terminal, const std::string &var_name)
void compilePluginImport(const Node &x, Page p)
void compileWhile(const Node &x, Page p)
void compileLetMutSet(Keyword n, const Node &x, Page p)
static bool isTernaryInst(Instruction inst) noexcept
Check if a given instruction is ternary (takes three arguments)
static bool isUnaryInst(Instruction inst) noexcept
Check if a given instruction is unary (takes only one argument)
const std::vector< ValTableElem > & values() const noexcept
Return the value table pre-computed.
static bool nodeProducesOutput(const Node &node)
std::vector< ValTableElem > m_values
void compileListInstruction(const Node &c0, const Node &x, Page p, bool is_result_unused)
IR::Block & page(const Page page) noexcept
helper functions to get a temp or finalized code page
const std::vector< std::string > & symbols() const noexcept
Return the symbol table pre-computed.
uint16_t addSymbol(const Node &sym)
Register a given node in the symbol table.
std::vector< std::string > m_symbols
void process(const Node &ast)
Start the compilation.
static std::optional< uint16_t > getBuiltin(const std::string &name) noexcept
Checking if a symbol is a builtin.
void compileIf(const Node &x, Page p, bool is_result_unused, bool is_terminal, const std::string &var_name)
static std::optional< Instruction > getOperator(const std::string &name) noexcept
Checking if a symbol is an operator.
IR::label_t m_current_label
static std::optional< Instruction > getListInstruction(const std::string &name) noexcept
Checking if a symbol is a list instruction.
void compileSymbol(const Node &x, Page p, bool is_result_unused)
void compileFunction(const Node &x, Page p, bool is_result_unused, const std::string &var_name)
const std::vector< IR::Block > & intermediateRepresentation() const noexcept
Return the IR blocks (one per scope)
static Entity Label(label_t value)
static Entity GotoIf(const Entity &label, bool cond)
static Entity Goto(const Entity &label)
void traceStart(std::string &&trace_name)
A node of an Abstract Syntax Tree for ArkScript.
NodeType nodeType() const noexcept
Return the node type.
const std::string & filename() const noexcept
Return the filename in which this node was created.
const std::string & string() const noexcept
Return the string held by the value (if the node type allows it)
const std::vector< Node > & constList() const noexcept
Return the list of sub-nodes held by the node.
std::string repr() const noexcept
Compute a representation of the node without any comments or additional sugar, colors,...
const Namespace & constArkNamespace() const noexcept
Return the namespace held by the value (if the node type allows it)
std::size_t col() const noexcept
Get the column at which this node was created.
std::size_t line() const noexcept
Get the line at which this node was created.
ARK_API std::string makeContextWithNode(const std::string &message, const internal::Node &node)
Helper used by the compiler to generate a colorized context from a node.
ARK_API const std::vector< std::pair< std::string, Value > > builtins
constexpr std::array< std::string_view, 9 > listInstructions
constexpr std::array< std::string_view, 24 > operators
constexpr std::string_view And
constexpr std::string_view Or
std::string typeToString(const Node &node) noexcept
Keyword
The different keywords available.
Instruction
The different bytecodes are stored here.
CodeError thrown by the compiler (parser, macro processor, optimizer, and compiler itself)
std::shared_ptr< Node > ast
A Compiler Value class helper to handle multiple types.