Skip to content

Commit

Permalink
feat(dto-compiler): Lay the foundations of a parser implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
whisperity committed Sep 23, 2023
1 parent efce74c commit 5350ba9
Show file tree
Hide file tree
Showing 19 changed files with 921 additions and 92 deletions.
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Checks: >-
-bugprone-macro-parantheses,
-bugprone-narrowing-conversions,
-cppcoreguidelines-avoid-c-arrays,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-macro-usage,
Expand Down
19 changes: 18 additions & 1 deletion include/core/monomux/adt/FunctionExtras.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@

#include "monomux/adt/Metaprogramming.hpp"

#define MONOMUX_MAKE_NON_COPYABLE(CLASS_NAME) \
CLASS_NAME(const CLASS_NAME&) = delete; \
CLASS_NAME& operator=(const CLASS_NAME&) = delete;
#define MONOMUX_MAKE_NON_MOVABLE(CLASS_NAME) \
CLASS_NAME(CLASS_NAME&&) = delete; \
CLASS_NAME& operator=(CLASS_NAME&&) = delete;
#define MONOMUX_MAKE_NON_COPYABLE_MOVABLE(CLASS_NAME) \
MONOMUX_MAKE_NON_COPYABLE(CLASS_NAME) \
MONOMUX_MAKE_NON_MOVABLE(CLASS_NAME)

#define MONOMUX_MAKE_STRICT_TYPE(CLASS_NAME, VIRTUAL_DTOR) \
CLASS_NAME() = default; \
MONOMUX_MAKE_NON_COPYABLE_MOVABLE(CLASS_NAME) \
VIRTUAL_DTOR ~CLASS_NAME() = default;

#define MONOMUX_DETAIL_FUNCTION_HEAD( \
RET_TY, NAME, ARGUMENTS, ATTRIBUTES, QUALIFIERS) \
ATTRIBUTES RET_TY NAME(ARGUMENTS) QUALIFIERS
Expand All @@ -17,11 +32,13 @@
#define MONOMUX_DETAIL_CONST_TYPE \
using Const = std::add_pointer_t< \
std::add_const_t<std::remove_pointer_t<decltype(this)>>>
#define MONOMUX_DETAIL_CONST_OBJ const_cast<Const>(this)
#define MONOMUX_DETAIL_CONST_VALUE(CALL) const auto& Value = CALL
/* NOLINTBEGIN(cppcoreguidelines-pro-type-const-cast) */
#define MONOMUX_DETAIL_CONST_OBJ const_cast<Const>(this)
/* NOLINTBEGIN(bugprone-macro-parantheses) */
#define MONOMUX_DETAIL_RETURN_CAST(RET_TY, OBJ) return const_cast<RET_TY>(OBJ)
/* NOLINTEND(bugprone-macro-parantheses) */
/* NOLINTEND(cppcoreguidelines-pro-type-const-cast) */

#define MONOMUX_DETAIL_FUNCTION_BODY(RET_TY, CALL) \
{ \
Expand Down
3 changes: 2 additions & 1 deletion include/core/monomux/adt/ScopeGuard.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ namespace monomux
/// \code{.cpp}
/// scope_guard RAII{[] { enter(); }, [] { exit(); }};
/// \endcode
template <typename EnterFunction, typename ExitFunction> struct ScopeGuard
template <typename EnterFunction, typename ExitFunction>
struct [[deprecated("Replace by scope_guard")]] ScopeGuard
{
ScopeGuard(EnterFunction&& Enter, ExitFunction&& Exit) : Exit(Exit)
{
Expand Down
88 changes: 88 additions & 0 deletions include/core/monomux/adt/scope_guard.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/* SPDX-License-Identifier: LGPL-3.0-only */
#pragma once
#include <memory>
#include <type_traits>

namespace monomux
{
/// A simple scope guard that fires an optional callback function when it is
/// constructed, and another callback function (usually, a lambda passed to the
/// constructor) when destructed.
///
/// Examples:
///
/// \code{.cpp}
/// scope_guard Cleanup{[] { exit(); }};
/// \endcode
///
/// \code{.cpp}
/// scope_guard RAII{[] { enter(); }, [] { exit(); }};
/// \endcode
template <typename EnterFunction, typename ExitFunction> struct scope_guard
{
// NOLINTNEXTLINE(google-explicit-constructor)
scope_guard(ExitFunction&& Exit) noexcept : Alive(true), Exit(Exit) {}
scope_guard(EnterFunction&& Enter,
ExitFunction&& Exit) noexcept(noexcept(Enter()))
: Alive(false), Exit(Exit)
{
Enter();
Alive = true; // NOLINT(cppcoreguidelines-prefer-member-initializer)
}

~scope_guard() noexcept(noexcept(Exit()))
{
if (Alive)
Exit();
Alive = false;
}

scope_guard() = delete;
scope_guard(const scope_guard&) = delete;
scope_guard(scope_guard&&) = delete;
scope_guard& operator=(const scope_guard&) = delete;
scope_guard& operator=(scope_guard&&) = delete;

private:
bool Alive;
ExitFunction Exit;
};

/// A simple scope guard that restores the value of a "captured" variable when
/// the scope is exited.
///
/// Example:
///
/// \code{.cpp}
/// int X = 4;
/// {
/// restore_guard Reset{X};
/// X = 6;
/// }
/// assert(X == 4);
/// \endcode
template <typename Ty> struct restore_guard
{
// NOLINTNEXTLINE(google-explicit-constructor)
restore_guard(Ty& Var) noexcept(std::is_copy_constructible_v<Ty>)
: Address(std::addressof(Var)), Value(Var)
{}

~restore_guard() noexcept(std::is_move_assignable_v<Ty>)
{
*Address = std::move(Value);
Address = nullptr;
}

restore_guard() = delete;
restore_guard(const restore_guard&) = delete;
restore_guard(restore_guard&&) = delete;
restore_guard& operator=(const restore_guard&) = delete;
restore_guard& operator=(restore_guard&&) = delete;

private:
Ty* Address;
Ty Value;
};

} // namespace monomux
13 changes: 13 additions & 0 deletions src/implementation/Monomux.dto
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@
namespace monomux::message
{

namespace test1
{
namespace test2
{
namespace test3::test4
{
}
}
}
namespace test5
{
}

literal ui64 APIMajor = 1;
literal ui64 APIMinor = 0;

Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ if (MONOMUX_BUILD_TESTS)

adt/MetaprogrammingTest.cpp
adt/RingBufferTest.cpp
adt/scope_guard_test.cpp
adt/SmallIndexMapTest.cpp
message/MessageSerialisationTest.cpp
)
Expand Down
37 changes: 37 additions & 0 deletions test/adt/scope_guard_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-3.0-only */
#include <gtest/gtest.h>

#include "monomux/adt/scope_guard.hpp"

/* NOLINTBEGIN(cert-err58-cpp,cppcoreguidelines-avoid-goto,cppcoreguidelines-owning-memory)
*/

using namespace monomux;

TEST(ScopeGuard, EntryAndExitCalled)
{
int Variable = 2;
{
ASSERT_EQ(Variable, 2);

scope_guard SG{[&Variable] { Variable = 4; },
[&Variable] { Variable = 0; }};
ASSERT_EQ(Variable, 4);
}
ASSERT_EQ(Variable, 0);
}

TEST(ScopeGuard, RestoreGuard)
{
int Variable = 2;
{
ASSERT_EQ(Variable, 2);
restore_guard RG{Variable};
Variable = 4;
ASSERT_EQ(Variable, 4);
}
ASSERT_EQ(Variable, 2);
}

/* NOLINTEND(cert-err58-cpp,cppcoreguidelines-avoid-goto,cppcoreguidelines-owning-memory)
*/
7 changes: 6 additions & 1 deletion tools/dto_compiler/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# SPDX-License-Identifier: LGPL-3.0-only
add_executable(dto_compiler
DTOCompiler.cpp
lex.cpp

dto_unit.cpp
lexer.cpp
parser.cpp

ast/decl.cpp
)
if (NOT MONOMUX_LIBRARY_TYPE STREQUAL "UNITY")
target_link_libraries(dto_compiler PUBLIC
Expand Down
35 changes: 26 additions & 9 deletions tools/dto_compiler/DTOCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#include <string>
#include <string_view>

#include "lex.hpp"
#include "dto_unit.hpp"
#include "lexer.hpp"
#include "parser.hpp"

namespace
{
Expand Down Expand Up @@ -57,17 +59,32 @@ int main(int ArgC, char* ArgV[])
std::cout << "Input string:\n" << InputBuffer << std::endl;

using namespace monomux::tools::dto_compiler;

lexer L{InputBuffer};
parser P{L};
bool Success = P.parse();
std::cout << P.get_unit().dump().str() << std::endl;

token T{};
while ((T = L.lex()) != token::EndOfFile)
if (!Success)
{
std::cout << to_string(L.get_token_info_raw()) << std::endl;
std::cerr << "ERROR! " << P.get_error().Location.Line << ':'
<< P.get_error().Location.Column << ": " << P.get_error().Reason
<< std::endl;
std::string_view ErrorLine = [&]() -> std::string_view {
auto RemainingRowCnt = P.get_error().Location.Line - 1;
std::size_t LinePos = 0;
while (RemainingRowCnt)
{
LinePos = InputBuffer.find('\n', LinePos) + 1;
--RemainingRowCnt;
}

if (T == token::SyntaxError)
{
std::cerr << "ERROR!" << std::endl;
return EXIT_FAILURE;
}
std::string_view Line = InputBuffer;
Line.remove_prefix(LinePos);
return Line.substr(0, Line.find('\n'));
}();
std::cerr << " " << ErrorLine << std::endl;
std::cerr << " " << std::string(P.get_error().Location.Column - 1, ' ')
<< '^' << std::endl;
}
}
68 changes: 68 additions & 0 deletions tools/dto_compiler/ast/decl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: LGPL-3.0-only */
#include <sstream>

#include "decl.hpp"

namespace monomux::tools::dto_compiler::ast
{

namespace
{

void print_ident(std::ostringstream& OS, std::size_t Indent)
{
if (Indent == 0)
OS << '.';

while (Indent > 1)
{
OS << "| ";
--Indent;
}
if (Indent == 1)
{
OS << "|- ";
}
}

} // namespace

void decl_context::dump_children(std::ostringstream& OS,
std::size_t Depth) const
{
for (const auto& Child : Children)
{
print_ident(OS, Depth);
Child->dump(OS, Depth + 1);
}
}

#define MONOMUX_DECL_DUMP(TYPE) \
void TYPE::dump(std::ostringstream& OS, std::size_t Depth) const

MONOMUX_DECL_DUMP(decl) {}

MONOMUX_DECL_DUMP(comment_decl)
{
static constexpr std::size_t CommentPrintLength = 64;
OS << "CommentDecl " << this << ' ';
OS << (Comment.is_block_comment() ? "block " : "line ");
OS << Comment.get_comment().substr(0, CommentPrintLength);
OS << '\n';
}

MONOMUX_DECL_DUMP(named_decl) {}

MONOMUX_DECL_DUMP(namespace_decl)
{
OS << "NamespaceDecl " << this << ' ' << get_identifier() << '\n';
dump_children(OS, Depth);
}

MONOMUX_DECL_DUMP(value_decl) {}

MONOMUX_DECL_DUMP(literal_decl) {}

#undef MONOMUX_DECL_DUMP

} // namespace monomux::tools::dto_compiler::ast
Loading

0 comments on commit 5350ba9

Please sign in to comment.