Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- `INCREMENT_BY_INDEX` and `DECREMENT_BY_INDEX` instructions for parity with the super instructions not using load by index
- `STORE_TAIL_BY_INDEX`, `STORE_HEAD_BY_INDEX`, `SET_VAL_TAIL_BY_INDEX`, `SET_VAL_HEAD_BY_INDEX` super instructions added for parity with the super instructions not using load by index
- `RESET_SCOPE` instruction emitted at the end of a while loop to reset a scope so that we can create multiple variables and use `LOAD_SYMBOL_BY_INDEX`
- instruction source location ; two new bytecode tables were added: one for filenames, another for (page pointer, instruction pointer, file id, line), allowing the VM to display better error messages when the source is available

### Changed
- instructions are on 4 bytes: 1 byte for the instruction, 1 byte of padding, 2 bytes for an immediate argument
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ if (ARK_TESTS)
--exclude 'tests/*'
--exclude 'lib/*'
--exclude '/usr/*'
--exclude 'build/*'
--gcov-tool ${ark_SOURCE_DIR}/tests/llvm-gcov.sh
--output-file coverage.info
# generate report
Expand Down
32 changes: 30 additions & 2 deletions include/Ark/Compiler/BytecodeReader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <Ark/Platform.hpp>
#include <Ark/Compiler/Common.hpp>
#include <Ark/VM/Value.hpp>
#include <Ark/Compiler/IntermediateRepresentation/InstLoc.hpp>

namespace Ark
{
Expand All @@ -31,7 +32,8 @@ namespace Ark
Symbols,
Values,
Code,
HeadersOnly
HeadersOnly,
InstructionLocation
};

struct Version
Expand All @@ -55,6 +57,20 @@ namespace Ark
std::size_t end {}; ///< Point to the byte following the last byte of the table in the bytecode
};

struct Filenames
{
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
};

struct InstLocations
{
std::vector<internal::InstLoc> locations {};
std::size_t start {}; ///< Point to the INST_LOC_TABLE_START byte in the bytecode
std::size_t end {}; ///< Point to the byte following the last byte of the table in the bytecode
};

struct Code
{
std::vector<bytecode_t> pages {};
Expand Down Expand Up @@ -129,9 +145,21 @@ namespace Ark

/**
* @param values
* @return Filenames
*/
[[nodiscard]] Filenames filenames(const Values& values) const;

/**
* @param filenames
* @return InstLocations
*/
[[nodiscard]] InstLocations instLocations(const Filenames& filenames) const;

/**
* @param instLocations
* @return Code
*/
[[nodiscard]] Code code(const Values& values) const;
[[nodiscard]] Code code(const InstLocations& instLocations) const;

/**
* @brief Display the bytecode opcode in a human friendly way.
Expand Down
6 changes: 4 additions & 2 deletions include/Ark/Compiler/Instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* @file Instructions.hpp
* @author Alexandre Plateau (lexplt.dev@gmail.com)
* @brief The different instructions used by the compiler and virtual machine
* @version 0.1
* @version 1.0
* @date 2020-10-27
*
* @copyright Copyright (c) 2020-2024
* @copyright Copyright (c) 2020-2025
*
*/

Expand Down Expand Up @@ -34,6 +34,8 @@ namespace Ark::internal
NUMBER_TYPE = 0xF1,
STRING_TYPE = 0xF2,
FUNC_TYPE = 0xF3,
FILENAMES_TABLE_START = 0xA4,
INST_LOC_TABLE_START = 0xA5,

// @args symbol id
// @role Load a symbol from its ID onto the stack
Expand Down
13 changes: 12 additions & 1 deletion include/Ark/Compiler/IntermediateRepresentation/Entity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @version 1.0
* @date 2024-10-05
*
* @copyright Copyright (c) 2024
* @copyright Copyright (c) 2024-2025
*
*/

Expand All @@ -14,6 +14,7 @@

#include <cinttypes>
#include <vector>
#include <string>

#include <Ark/Compiler/IntermediateRepresentation/Word.hpp>
#include <Ark/Compiler/Instructions.hpp>
Expand Down Expand Up @@ -62,12 +63,22 @@ namespace Ark::internal::IR

[[nodiscard]] inline uint16_t secondaryArg() const { return m_secondary_arg; }

void setSourceLocation(const std::string& filename, std::size_t line);

[[nodiscard]] inline bool hasValidSourceLocation() const { return !m_source_file.empty(); }

[[nodiscard]] inline const std::string& filename() const { return m_source_file; }

[[nodiscard]] inline std::size_t sourceLine() const { return m_source_line; }

private:
Kind m_kind;
label_t m_label { 0 };
Instruction m_inst { NOP };
uint16_t m_primary_arg { 0 };
uint16_t m_secondary_arg { 0 };
std::string m_source_file;
std::size_t m_source_line { 0 };
};

using Block = std::vector<Entity>;
Expand Down
16 changes: 8 additions & 8 deletions include/Ark/Compiler/IntermediateRepresentation/IRCompiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* @file IRCompiler.hpp
* @author Alexandre Plateau (lexplt.dev@gmail.com)
* @brief Compile the intermediate representation to bytecode
* @version 0.1
* @version 0.2
* @date 2024-10-05
*
* @copyright Copyright (c) 2024
* @copyright Copyright (c) 2024-2025
*
*/

Expand Down Expand Up @@ -60,11 +60,12 @@ namespace Ark::internal
Logger m_logger;
bytecode_t m_bytecode;
std::vector<IR::Block> m_ir;
std::vector<std::string> m_filenames;

void compile();

/**
* @brief Push a word to the m_bytecode
* @brief Push a word (4 bytes) to the m_bytecode
* @param word
*/
void pushWord(const Word& word);
Expand All @@ -75,11 +76,10 @@ namespace Ark::internal
*/
void pushFileHeader() noexcept;

/**
* @brief Push the symbols and values tables
*
*/
void pushSymAndValTables(const std::vector<std::string>& symbols, const std::vector<ValTableElem>& values);
void pushSymbolTable(const std::vector<std::string>& symbols);
void pushValueTable(const std::vector<ValTableElem>& values);
void pushFilenameTable();
void pushInstLocTable(const std::vector<IR::Block>& pages);
};
}

Expand Down
18 changes: 18 additions & 0 deletions include/Ark/Compiler/IntermediateRepresentation/InstLoc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef ARK_COMPILER_INTERMEDIATEREPRESENTATION_INSTLOC_HPP
#define ARK_COMPILER_INTERMEDIATEREPRESENTATION_INSTLOC_HPP

#include <cstdint>

namespace Ark::internal
{
// pp (2 bytes), ip (2 bytes), filename id (2 bytes), line (4 bytes) -> 10 bytes per record
struct InstLoc
{
uint16_t page_pointer;
uint16_t inst_pointer;
uint16_t filename_id;
uint32_t line;
};
}

#endif // ARK_COMPILER_INTERMEDIATEREPRESENTATION_INSTLOC_HPP
12 changes: 6 additions & 6 deletions include/Ark/Compiler/Serialization/IntegerSerializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ namespace Ark::internal
void serializeOn2BytesToVecLE(std::integral auto number, std::vector<uint8_t>& out)
{
constexpr auto mask = static_cast<decltype(number)>(0xff);
for (std::size_t i = 0; i < 2; ++i)
out.push_back(static_cast<uint8_t>((number & (mask << (8 * i))) >> (8 * i)));
out.push_back(static_cast<uint8_t>(number & mask));
out.push_back(static_cast<uint8_t>((number & (mask << 8)) >> 8));
}

void serializeOn2BytesToVecBE(std::integral auto number, std::vector<uint8_t>& out)
{
constexpr auto mask = static_cast<decltype(number)>(0xff);
for (std::size_t i = 0; i < 2; ++i)
out.push_back(static_cast<uint8_t>((number & (mask << (8 * (1 - i)))) >> (8 * (1 - i))));
out.push_back(static_cast<uint8_t>((number & (mask << 8)) >> 8));
out.push_back(static_cast<uint8_t>(number & mask));
}

template <std::integral T>
Expand All @@ -55,10 +55,10 @@ namespace Ark::internal
template <std::integral T>
T deserializeBE(std::vector<uint8_t>::const_iterator begin, std::vector<uint8_t>::const_iterator end)
{
constexpr std::size_t length = sizeof(T) - 1;
constexpr std::size_t length = sizeof(T);
T result {};
for (std::size_t i = 0; i < length && begin != end; ++i, ++begin)
result += static_cast<T>(*begin) << (8 * (length - i));
result += static_cast<T>(*begin) << (8 * (length - i - 1));

return result;
}
Expand Down
56 changes: 38 additions & 18 deletions include/Ark/Exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @version 1.3
* @date 2020-10-27
*
* @copyright Copyright (c) 2020-2024
* @copyright Copyright (c) 2020-2025
*
*/

Expand Down Expand Up @@ -35,6 +35,11 @@ namespace Ark
explicit Error(const std::string& message) :
std::runtime_error(message)
{}

[[nodiscard]] virtual std::string details(bool colorize [[maybe_unused]]) const
{
return what();
}
};

/**
Expand All @@ -49,22 +54,6 @@ namespace Ark
{}
};

/**
* @brief A special zero division error triggered when a number is divided by 0
*
*/
class ARK_API ZeroDivisionError final : public Error
{
public:
ZeroDivisionError() :
Error(
"ZeroDivisionError: In ordinary arithmetic, the expression has no meaning, "
"as there is no number which, when multiplied by 0, gives a (assuming a != 0), "
"and so division by zero is undefined. Since any number multiplied by 0 is 0, "
"the expression 0/0 is also undefined.")
{}
};

/**
* @brief An assertion error, only triggered from ArkScript code through (assert expr error-message)
*
Expand All @@ -77,6 +66,36 @@ namespace Ark
{}
};

class ARK_API NestedError final : public Error
{
public:
NestedError(const Error& e, const std::string& details) :
Error("NestedError"),
m_details(e.details(/* colorize= */ false))
{
if (!m_details.empty() && m_details.back() != '\n')
m_details += '\n';
m_details += "\n" + details;
}

NestedError(const std::exception& e, const std::string& details) :
Error("NestedError"),
m_details(e.what())
{
if (!m_details.empty() && m_details.back() != '\n')
m_details += '\n';
m_details += "\n" + details;
}

[[nodiscard]] const char* what() const noexcept override
{
return m_details.c_str();
}

private:
std::string m_details;
};

/**
* @brief CodeError thrown by the compiler (parser, macro processor, optimizer, and compiler itself)
*
Expand Down Expand Up @@ -111,9 +130,10 @@ namespace Ark
* @param target_line line where the error is
* @param col_start where the error starts on the given line
* @param sym_size bad expression that triggered the error
* @param whole_line when true, underline the whole line, disregarding col_start and sym_size
* @param colorize generate colors or not
*/
ARK_API void makeContext(std::ostream& os, const std::string& code, std::size_t target_line, std::size_t col_start, std::size_t sym_size, bool colorize);
ARK_API void makeContext(std::ostream& os, const std::string& code, std::size_t target_line, std::size_t col_start, std::size_t sym_size, bool whole_line, bool colorize);

/**
* @brief Helper used by the compiler to generate a colorized context from a node
Expand Down
29 changes: 27 additions & 2 deletions include/Ark/TypeChecker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @version 1.1
* @date 2022-01-16
*
* @copyright Copyright (c) 2022-2024
* @copyright Copyright (c) 2022-2025
*
*/

Expand All @@ -15,7 +15,9 @@
#include <string>
#include <vector>
#include <ostream>
#include <sstream>

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

namespace Ark::types
Expand Down Expand Up @@ -94,12 +96,35 @@ namespace Ark::types
* @param os output stream, default to cout
* @param colorize enable output colorizing
*/
ARK_API void generateError [[noreturn]] (
ARK_API void generateError(
const std::string_view& funcname,
const std::vector<Contract>& contracts,
const std::vector<Value>& args,
std::ostream& os = std::cout,
bool colorize = true);

class ARK_API TypeCheckingError : public Error
{
public:
TypeCheckingError(std::string&& funcname, const std::vector<Contract>& contracts, const std::vector<Value>& args) :
Error("TypeCheckingError"),
m_funcname(std::move(funcname)),
m_contracts(contracts),
m_passed_args(args)
{}

[[nodiscard]] std::string details(const bool colorize) const override
{
std::stringstream stream;
generateError(m_funcname, m_contracts, m_passed_args, stream, colorize);
return stream.str();
}

private:
std::string m_funcname;
std::vector<Contract> m_contracts;
std::vector<Value> m_passed_args;
};
}

#endif
Loading
Loading