Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change Log

## [Unreleased changes] - 20XX-XX-XX
### Breaking changes
- `assert` is no longer an instruction but a builtin

### Added
- added `BREAKPOINT` instruction

## [4.1.2] - 2026-01-09
### Added
- the repl prints the output of the last expression it ran
Expand Down
3 changes: 1 addition & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ if (NOT ARK_EMSCRIPTEN)
endif ()

include(cmake/CPM.cmake)
message(STATUS "ArkScript version ${ARK_VERSION_MAJOR}.${ARK_VERSION_MINOR}.${ARK_VERSION_PATCH}-${ARK_COMMIT}")

#####################################################
# Configure files
Expand All @@ -55,9 +56,7 @@ include(cmake/CPM.cmake)
configure_file(
${ark_SOURCE_DIR}/Installer.iss.in
${ark_SOURCE_DIR}/Installer.iss)

## Ark/Constants.hpp
message(STATUS "ArkScript version ${ARK_VERSION_MAJOR}.${ARK_VERSION_MINOR}.${ARK_VERSION_PATCH}-${ARK_COMMIT}")
configure_file(
${ark_SOURCE_DIR}/include/Ark/Constants.hpp.in
${ark_SOURCE_DIR}/include/Ark/Constants.hpp)
Expand Down
3 changes: 2 additions & 1 deletion include/Ark/Ark.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
#include <Ark/Error/Exceptions.hpp>
#include <Ark/Constants.hpp>
#include <Ark/Utils/Utils.hpp>
#include <Ark/Compiler/Welder.hpp>
#include <Ark/State.hpp>
#include <Ark/VM/VM.hpp>
#include <Ark/VM/DefaultValues.hpp>
#include <Ark/Compiler/Welder.hpp>
#include <Ark/TypeChecker.hpp>

#endif // ARK_ARK_HPP
3 changes: 2 additions & 1 deletion include/Ark/Builtins/Builtins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

#include <vector>

#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>

namespace Ark
{
Expand Down Expand Up @@ -70,6 +70,7 @@ namespace Ark::internal::Builtins
ARK_BUILTIN(system_);
ARK_BUILTIN(sleep);
ARK_BUILTIN(exit_);
ARK_BUILTIN(assert_);
}

namespace String
Expand Down
2 changes: 1 addition & 1 deletion include/Ark/Compiler/BytecodeReader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#include <Ark/Utils/Platform.hpp>
#include <Ark/Compiler/Common.hpp>
#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>
#include <Ark/Compiler/IntermediateRepresentation/InstLoc.hpp>

namespace Ark
Expand Down
4 changes: 2 additions & 2 deletions include/Ark/Compiler/Common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ namespace Ark::internal
// from FIRST_OPERATOR, to LAST_OPERATOR
// The order is very important
constexpr std::array<std::string_view, 24> operators = {
"breakpoint",
"+", "-", "*", "/",
">", "<", "<=", ">=", "!=", "=",
"len", "empty?", "tail", "head",
"nil?", "assert",
"len", "empty?", "tail", "head", "nil?",
"toNumber", "toString",
"@", "@@", "mod",
"type", "hasField",
Expand Down
38 changes: 19 additions & 19 deletions include/Ark/Compiler/Instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,53 +173,53 @@ namespace Ark::internal

FIRST_OPERATOR = 0x26,

// @role Pop the top of the stack, if it's true, trigger the debugger
BREAKPOINT = 0x26,

// @role Push `TS1 + TS`
ADD = 0x26,
ADD = 0x27,

// @role Push `TS1 - TS`
SUB = 0x27,
SUB = 0x28,

// @role Push `TS1 * TS`
MUL = 0x28,
MUL = 0x29,

// @role Push `TS1 / TS`
DIV = 0x29,
DIV = 0x2a,

// @role Push `TS1 > TS`
GT = 0x2a,
GT = 0x2b,

// @role Push `TS1 < TS`
LT = 0x2b,
LT = 0x2c,

// @role Push `TS1 <= TS`
LE = 0x2c,
LE = 0x2d,

// @role Push `TS1 >= TS`
GE = 0x2d,
GE = 0x2e,

// @role Push `TS1 != TS`
NEQ = 0x2e,
NEQ = 0x2f,

// @role Push `TS1 == TS`
EQ = 0x2f,
EQ = 0x30,

// @role Push `len(TS)`, TS must be a list
LEN = 0x30,
LEN = 0x31,

// @role Push `empty?(TS)`, TS must be a list or string
IS_EMPTY = 0x31,
IS_EMPTY = 0x32,

// @role Push `tail(TS)`, all the elements of TS except the first one. TS must be a list or string
TAIL = 0x32,
TAIL = 0x33,

// @role Push `head(TS)`, the first element of TS or nil if empty. TS must be a list or string
HEAD = 0x33,
HEAD = 0x34,

// @role Push true if TS is nil, false otherwise
IS_NIL = 0x34,

// @role Throw an exception if TS1 is false, and display TS (must be a string). Do not push anything on the stack
ASSERT = 0x35,
IS_NIL = 0x35,

// @role Convert TS to number (must be a string)
TO_NUM = 0x36,
Expand Down Expand Up @@ -492,6 +492,7 @@ namespace Ark::internal
"POP_SCOPE",
"GET_CURRENT_PAGE_ADDR",
// operators
"BREAKPOINT",
"ADD",
"SUB",
"MUL",
Expand All @@ -507,7 +508,6 @@ namespace Ark::internal
"TAIL",
"HEAD",
"IS_NIL",
"ASSERT",
"TO_NUM",
"TO_STR",
"AT",
Expand Down
8 changes: 8 additions & 0 deletions include/Ark/Compiler/Lowerer/ASTLowerer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ namespace Ark::internal
*/
static std::optional<Instruction> getListInstruction(const std::string& name) noexcept;

/**
* Checks if a node is a list and is a call to 'breakpoint'
* @param node node to check
* @return true if the node is a 'breakpoint' call: (breakpoint <cond>)
* @return false otherwise
*/
static bool isBreakpoint(const Node& node);

/**
* Checks if a node is a list and has a keyboard as its first node, indicating if it's producing a value on the stack or not
* @param node node to check
Expand Down
1 change: 1 addition & 0 deletions include/Ark/Constants.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ namespace Ark
constexpr uint16_t FeatureASTOptimizer = 1 << 2; ///< This is disabled so that embedding ArkScript does not prune nodes from the AST ; it is active in the `arkscript` executable
constexpr uint16_t FeatureIROptimizer = 1 << 3;
constexpr uint16_t FeatureNameResolver = 1 << 4;
constexpr uint16_t FeatureVMDebugger = 1 << 5; ///< This is disabled so that embedding ArkScript does not launch the debugger on every error when running code

constexpr uint16_t FeatureDumpIR = 1 << 14;
/// This feature should only be used in tests, to disable diagnostics generation and enable exceptions to be thrown
Expand Down
8 changes: 4 additions & 4 deletions include/Ark/VM/State.hpp → include/Ark/State.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include <filesystem>
#include <Ark/Constants.hpp>

#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>
#include <Ark/VM/Value/Procedure.hpp>
#include <Ark/Compiler/Common.hpp>
#include <Ark/Error/Exceptions.hpp>
Expand Down Expand Up @@ -131,18 +131,18 @@ namespace Ark
*
* @param file the path of file code to compile
* @param output set path of .arkc file
* @param features compiler features to enable/disable
* @return true on success
* @return false on failure and raise an exception
*/
[[nodiscard]] bool compile(const std::string& file, const std::string& output, uint16_t features) const;
[[nodiscard]] bool compile(const std::string& file, const std::string& output) const;

static void throwStateError(const std::string& message)
{
throw Error("StateError: " + message);
}

unsigned m_debug_level;
uint16_t m_features;

bytecode_t m_bytecode;
std::vector<std::filesystem::path> m_libenv;
Expand All @@ -157,7 +157,7 @@ namespace Ark
bytecode_t m_code;

// related to the execution
std::unordered_map<std::string, Value> m_binded; ///< Values binded to the State, to be used by the VM
std::unordered_map<std::string, Value> m_bound; ///< Values bound to the State, to be used by the VM

/**
* @brief Get an instruction in a given page, with a given instruction pointer
Expand Down
2 changes: 1 addition & 1 deletion include/Ark/TypeChecker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include <sstream>

#include <Ark/Error/Exceptions.hpp>
#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>

namespace Ark
{
Expand Down
52 changes: 52 additions & 0 deletions include/Ark/VM/Debugger.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* @file Debugger.hpp
* @author Lexy Plateau (lexplt.dev@gmail.com)
* @brief Debugger used by the VM when an error or a breakpoint is reached
* @date 2026-01-12
*
* @copyright Copyright (c) 2026-01-12
*
*/

#ifndef ARK_VM_DEBUGGER_HPP
#define ARK_VM_DEBUGGER_HPP

#include <Ark/VM/ExecutionContext.hpp>

#include <vector>
#include <memory>

namespace Ark::internal
{
struct SavedState
{
std::size_t ip;
std::size_t pp;
uint16_t sp;
uint16_t fc;
std::vector<ScopeView> locals;
std::vector<std::shared_ptr<ClosureScope>> closure_scopes;
};

class Debugger
{
public:
/**
* @brief Create a new Debugger object
*
* @param context context from the VM before displaying a backtrace
*/
explicit Debugger(const ExecutionContext& context);

void saveState(const ExecutionContext& context);

void resetContextToErrorState(ExecutionContext& context);

void run();

private:
std::vector<std::unique_ptr<SavedState>> m_states;
};
}

#endif // ARK_VM_DEBUGGER_HPP
2 changes: 1 addition & 1 deletion include/Ark/VM/DefaultValues.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#ifndef ARK_VM_DEFAULTVALUES_HPP
#define ARK_VM_DEFAULTVALUES_HPP

#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>

namespace Ark
{
Expand Down
2 changes: 1 addition & 1 deletion include/Ark/VM/ExecutionContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include <atomic>

#include <Ark/Constants.hpp>
#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>
#include <Ark/VM/ScopeView.hpp>
#include <Ark/VM/Value/ClosureScope.hpp>

Expand Down
4 changes: 2 additions & 2 deletions include/Ark/VM/ScopeView.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @file Scope.hpp
* @file ScopeView.hpp
* @author Lexy Plateau (lexplt.dev@gmail.com)
* @brief The virtual machine scope system
* @date 2020-10-27
Expand All @@ -15,7 +15,7 @@
#include <cinttypes>

#include <Ark/Utils/Platform.hpp>
#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>

namespace Ark::internal
{
Expand Down
14 changes: 9 additions & 5 deletions include/Ark/VM/VM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@
#include <fmt/ranges.h>

#include <Ark/Compiler/Instructions.hpp>
#include <Ark/VM/Value.hpp>
#include <Ark/VM/State.hpp>
#include <Ark/VM/Value/Value.hpp>
#include <Ark/State.hpp>
#include <Ark/VM/ScopeView.hpp>
#include <Ark/VM/ErrorKind.hpp>
#include <Ark/VM/ExecutionContext.hpp>
#include <Ark/Builtins/Builtins.hpp>
#include <Ark/Utils/Platform.hpp>
#include <Ark/Utils/Literals.hpp>
#include <Ark/VM/SharedLibrary.hpp>
#include <Ark/VM/Future.hpp>
#include <Ark/VM/Value/Future.hpp>
#include <Ark/VM/Debugger.hpp>

namespace Ark
{
Expand Down Expand Up @@ -175,6 +176,7 @@ namespace Ark
std::mutex m_mutex, m_mutex_futures;
std::vector<std::shared_ptr<internal::SharedLibrary>> m_shared_lib_objects;
std::vector<std::unique_ptr<internal::Future>> m_futures; ///< Storing the promises while we are resolving them
std::unique_ptr<internal::Debugger> m_debugger { nullptr };

// a little trick for operator[] and for pop
Value m_no_value = internal::Builtins::nil;
Expand Down Expand Up @@ -352,6 +354,8 @@ namespace Ark

[[noreturn]] void throwArityError(std::size_t passed_arg_count, std::size_t expected_arg_count, internal::ExecutionContext& context);

void initDebugger(internal::ExecutionContext& context);

void showBacktraceWithException(const std::exception& e, internal::ExecutionContext& context);

/**
Expand All @@ -361,9 +365,9 @@ namespace Ark
* @param pp
* @return std::optional<InstLoc>
*/
std::optional<internal::InstLoc> findSourceLocation(std::size_t ip, std::size_t pp) const;
[[nodiscard]] std::optional<internal::InstLoc> findSourceLocation(std::size_t ip, std::size_t pp) const;

std::string debugShowSource() const;
[[nodiscard]] std::string debugShowSource() const;

/**
* @brief Display a backtrace when the VM encounter an exception
Expand Down
2 changes: 1 addition & 1 deletion include/Ark/VM/Value/ClosureScope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <cinttypes>

#include <Ark/Utils/Platform.hpp>
#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>

namespace Ark::internal
{
Expand Down
2 changes: 1 addition & 1 deletion include/Ark/VM/Value/Dict.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#ifndef ARK_VM_VALUE_DICT_HPP
#define ARK_VM_VALUE_DICT_HPP

#include <Ark/VM/Value.hpp>
#include <Ark/VM/Value/Value.hpp>
#include <Ark/Utils/Platform.hpp>

#include <ankerl/unordered_dense.h>
Expand Down
Loading
Loading