Skip to content
Open
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
16 changes: 9 additions & 7 deletions .clang-format-ignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
bitwise/documentation
console/documentation
hash/documentation
http/documentation
http/bulk_req.py
json/documentation
random/documentation
src/bitwise/documentation
src/console/documentation
src/hash/documentation
src/http/documentation
src/http/bulk_req.py

draft/database/documentation
draft/json/documentation
draft/re/documentation
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
build/
cmake-build-*/
__pycache__/
__arkscript__/
cformat.ps1

.idea/

cmake-build-*/
build/
*.o
*.out
*.dll
Expand All @@ -15,4 +13,3 @@ build/
*.so

draft/playground

6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@
[submodule "submodules/termcolor"]
path = submodules/termcolor
url = https://github.com/ikalnytskyi/termcolor
[submodule "submodules/abseil"]
path = submodules/abseil
url = https://github.com/abseil/abseil-cpp.git
[submodule "submodules/re2"]
path = submodules/re2
url = https://github.com/google/re2.git
1 change: 1 addition & 0 deletions draft/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(database)
add_subdirectory(json)
add_subdirectory(re)
27 changes: 27 additions & 0 deletions draft/re/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.16)

project(re)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

set(ABSL_ENABLE_INSTALL ON)
set(ABSL_PROPAGATE_CXX_STD ON)
add_subdirectory(${Modules_SOURCE_DIR}/submodules/abseil abseil EXCLUDE_FROM_ALL SYSTEM)
add_subdirectory(${Modules_SOURCE_DIR}/submodules/re2 re2 EXCLUDE_FROM_ALL SYSTEM)

include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB_RECURSE SOURCE_FILES
${PROJECT_SOURCE_DIR}/src/*.cpp
${ark_SOURCE_DIR}/thirdparties/fmt/src/format.cc)

add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES})

target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE ${ark_SOURCE_DIR}/include)
target_link_libraries(${PROJECT_NAME} PRIVATE ArkReactor re2::re2)

target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)

add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"$<TARGET_FILE:${PROJECT_NAME}>" ${ark_SOURCE_DIR}/lib/${PROJECT_NAME}.arkm)
Empty file added draft/re/README.md
Empty file.
Empty file.
19 changes: 19 additions & 0 deletions draft/re/include/module.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef RE_REGEX_HPP
#define RE_REGEX_HPP

#include <Ark/Module.hpp>

namespace Regex
{
using namespace Ark;

Value search(std::vector<Value>& args, VM* vm);
Value match(std::vector<Value>& args, VM* vm);
Value full_match(std::vector<Value>& args, VM* vm);
Value find_all(std::vector<Value>& args, VM* vm);
Value sub(std::vector<Value>& args, VM* vm);
Value split(std::vector<Value>& args, VM* vm);
Value escape(std::vector<Value>& args, VM* vm);
}

#endif // RE_REGEX_HPP
63 changes: 63 additions & 0 deletions draft/re/include/utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#ifndef RE_UTILS_HPP
#define RE_UTILS_HPP

#include <vector>
#include <string>

#include <re2/re2.h>
#include <absl/strings/string_view.h>

namespace Regex
{
struct Span
{
long start;
std::size_t size;
bool empty;
};

struct Match
{
std::vector<Span> spans;

[[nodiscard]] inline long start() const
{
return spans.front().start;
}

[[nodiscard]] inline std::size_t end() const
{
return spans.front().start + spans.front().size;
}

[[nodiscard]] inline std::size_t size() const
{
return spans.front().size;
}
};

struct MatchImpl_t
{
std::string text;
std::vector<Match> matches;
bool empty;
bool expect_many;
};

inline Span asSpan(const absl::string_view& sv, const std::string& text)
{
return Span { .start = static_cast<long>(sv.data() - text.data()), .size = sv.size(), .empty = false };
}

inline Span getFirstSpan(const std::vector<absl::string_view>& groups, const std::string& text)
{
if (const auto& it = groups.front(); it.data() == nullptr)
return Span { .start = 0, .size = 0, .empty = true };
else
return asSpan(it, text);
}

MatchImpl_t matchImpl(RE2::Anchor anchor, const std::string& regex, const std::string& text, bool stop_at_first);
}

#endif // RE_UTILS_HPP
184 changes: 184 additions & 0 deletions draft/re/src/impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#include <Ark/VM/Value/Dict.hpp>
#include <module.hpp>
#include <utils.hpp>

#include <vector>
#include <ranges>

#include <re2/re2.h>

namespace Regex
{
using namespace Ark;
using namespace Ark::literals;
using namespace re2;

Value toValue(const Match& match, const std::string& text)
{
internal::Dict dict;
const auto& span = match.spans.front();
if (!span.empty)
dict.set(Value("match"), Value(text.substr(span.start, span.size)));
else
dict.set(Value("match"), Nil);
dict.set(Value("start"), Value(static_cast<int64_t>(span.start)));
dict.set(Value("end"), Value(static_cast<int64_t>(span.size + span.start)));

Value groups(ValueType::List);
for (const Span& s : match.spans | std::ranges::views::drop(1))
groups.push_back(Value(text.substr(s.start, s.size)));
dict.set(Value("groups"), groups);

return Value(std::move(dict));
}

Value toValue(const MatchImpl_t& res)
{
if (res.empty)
return Nil;

if (res.expect_many)
{
Value output(ValueType::List);
for (const Match& match : res.matches)
{
// todo: create a dict with all the groups
output.push_back(toValue(match, res.text));
}
return output;
}

const Match& match = res.matches.front();
return toValue(match, res.text);
}

Value search(std::vector<Value>& args, VM* vm)
{
if (!types::check(args, ValueType::String, ValueType::String))
throw types::TypeCheckingError(
"re:search",
{ { types::Contract { { types::Typedef("regex", ValueType::String), types::Typedef("input", ValueType::String) } } } },
args);
const std::string& regex = args[0].string();
const std::string& input = args[1].string();
return toValue(matchImpl(RE2::UNANCHORED, regex, input, true));
}

Value match(std::vector<Value>& args, VM* vm)
{
if (!types::check(args, ValueType::String, ValueType::String))
throw types::TypeCheckingError(
"re:match",
{ { types::Contract { { types::Typedef("regex", ValueType::String), types::Typedef("input", ValueType::String) } } } },
args);
const std::string& regex = args[0].string();
const std::string& input = args[1].string();
return toValue(matchImpl(RE2::ANCHOR_START, regex, input, true));
}

Value full_match(std::vector<Value>& args, VM* vm)
{
if (!types::check(args, ValueType::String, ValueType::String))
throw types::TypeCheckingError(
"re:fullMatch",
{ { types::Contract { { types::Typedef("regex", ValueType::String), types::Typedef("input", ValueType::String) } } } },
args);
const std::string& regex = args[0].string();
const std::string& input = args[1].string();
return toValue(matchImpl(RE2::ANCHOR_BOTH, regex, input, true));
}

Value find_all(std::vector<Value>& args, VM* vm)
{
if (!types::check(args, ValueType::String, ValueType::String))
throw types::TypeCheckingError(
"re:findAll",
{ { types::Contract { { types::Typedef("regex", ValueType::String), types::Typedef("input", ValueType::String) } } } },
args);
const std::string& regex = args[0].string();
const std::string& input = args[1].string();
return toValue(matchImpl(RE2::UNANCHORED, regex, input, false));
}

Value sub(std::vector<Value>& args, VM* vm)
{
if (!types::check(args, ValueType::String, ValueType::String, ValueType::String))
throw types::TypeCheckingError(
"re:sub",
{ { types::Contract { { types::Typedef("regex", ValueType::String),
types::Typedef("replacement", ValueType::String),
types::Typedef("input", ValueType::String) } } } },
args);
const std::string& regex = args[0].string();
const std::string& replacement = args[1].string();
std::string input = args[2].string();

// todo: control how many times we want to replace?
RE2::GlobalReplace(&input, regex, replacement);
return Value(input);
}

Value split(std::vector<Value>& args, VM* vm)
{
if (!types::check(args, ValueType::String, ValueType::String) && !types::check(args, ValueType::String, ValueType::String, ValueType::Number))
throw types::TypeCheckingError(
"re:split",
{ { types::Contract {
{ types::Typedef("regex", ValueType::String),
types::Typedef("input", ValueType::String) } },
types::Contract { { types::Typedef("regex", ValueType::String),
types::Typedef("input", ValueType::String),
types::Typedef("max_split", ValueType::Number) } } } },
args);
const std::string& regex = args[0].string();
const std::string& input = args[1].string();
long max_split = 0;
if (args.size() == 3)
max_split = static_cast<long>(args[2].number());

Value output(ValueType::List);
if (max_split < 0)
{
output.push_back(args[1]);
return output;
}

long num_split = 0;
std::size_t end = 0;
const MatchImpl_t res = matchImpl(RE2::UNANCHORED, regex, input, false);
if (res.empty)
return Nil;

for (const Match& match : res.matches)
{
output.push_back(Value(res.text.substr(end, match.start() - end)));
for (std::size_t i = 1; i < match.spans.size(); ++i)
{
if (!match.spans[i].empty)
output.push_back(Value(res.text.substr(match.spans[i].start, match.spans[i].size)));
else
output.push_back(Nil);
}

end = match.end();
num_split++;

if (num_split == max_split)
break;
}
if (end < res.text.size())
output.push_back(Value(res.text.substr(end)));

return output;
}

Value escape(std::vector<Value>& args, VM* vm)
{
if (!types::check(args, ValueType::String))
throw types::TypeCheckingError(
"re:escape",
{ { types::Contract { { types::Typedef("text", ValueType::String) } } } },
args);
return Value(RE2::QuoteMeta(args[0].string()));
}
}
17 changes: 17 additions & 0 deletions draft/re/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <module.hpp>

ARK_API Ark::mapping* getFunctionsMapping()
{
static Ark::mapping map[] = {
{ "re:search", Regex::search },
{ "re:match", Regex::match },
{ "re:fullMatch", Regex::full_match },
{ "re:findAll", Regex::find_all },
{ "re:sub", Regex::sub },
{ "re:split", Regex::split },
{ "re:escape", Regex::escape },
{ nullptr, nullptr }
};

return map;
}
Loading
Loading