first commit
This commit is contained in:
commit
0e05000b7d
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: true
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
ColumnLimit: 180
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 2
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
|
||||
BraceWrapping:
|
||||
AfterEnum: false
|
||||
|
||||
AlignConsecutiveDeclarations: AcrossEmptyLines
|
||||
|
||||
NamespaceIndentation: All
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
cmake-build*
|
||||
|
||||
.idea
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "external/ctre"]
|
||||
path = external/ctre
|
||||
url = https://github.com/hanickadot/compile-time-regular-expressions.git
|
|
@ -0,0 +1,22 @@
|
|||
cmake_minimum_required(VERSION 3.30)
|
||||
project(nutri)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 26)
|
||||
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(cpr REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/external/ctre/include)
|
||||
add_subdirectory(external/ctre/)
|
||||
|
||||
add_executable(
|
||||
nutri
|
||||
src/main.cpp
|
||||
src/ArgParser.hpp
|
||||
src/Helpers/Utility.cpp
|
||||
src/Helpers/Utility.hpp
|
||||
src/Helpers/WolframAlpha.hpp
|
||||
src/Helpers/WolframAlpha.cpp)
|
||||
|
||||
target_link_libraries(nutri PRIVATE cpr::cpr nlohmann_json::nlohmann_json ctre::ctre)
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
from cpt.packager import ConanMultiPackager
|
||||
|
||||
|
||||
def get_travis_branch():
|
||||
return os.getenv("TRAVIS_BRANCH")
|
||||
|
||||
|
||||
def get_reference():
|
||||
return "CTRE/{}".format(get_travis_branch())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
builder = ConanMultiPackager(
|
||||
reference=get_reference(),
|
||||
username="ctre",
|
||||
upload="https://api.bintray.com/conan/hanickadot/ctre",
|
||||
upload_only_when_stable=True,
|
||||
stable_branch_pattern="v?\d+\.\d+.*",
|
||||
test_folder=os.path.join(".conan", "test_package"))
|
||||
builder.add_common_builds()
|
||||
builder.run()
|
|
@ -0,0 +1,11 @@
|
|||
project(test_package CXX)
|
||||
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE TRUE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
|
||||
add_executable(${PROJECT_NAME} test_package.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from conans import ConanFile, CMake, tools, RunEnvironment
|
||||
import os
|
||||
|
||||
|
||||
class TestPackageConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
generators = "cmake"
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def test(self):
|
||||
assert os.path.exists(os.path.join(self.deps_cpp_info["CTRE"].rootpath, "licenses", "LICENSE"))
|
||||
bin_path = os.path.join("bin", "test_package")
|
||||
self.run(bin_path, run_environment=True)
|
|
@ -0,0 +1,32 @@
|
|||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
|
||||
#include <ctre.hpp>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using namespace ctre::literals;
|
||||
|
||||
struct date { std::string_view year; std::string_view month; std::string_view day; };
|
||||
|
||||
static constexpr ctll::fixed_string pattern = "^([0-9]{4})/([0-9]{1,2}+)/([0-9]{1,2}+)$";
|
||||
|
||||
constexpr std::optional<date> extract_date(std::string_view s) noexcept {
|
||||
if (auto [whole, year, month, day] = ctre::match<pattern>(s); whole
|
||||
) {
|
||||
return date{year.to_view(), month.to_view(), day.to_view()};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
assert(extract_date("2018/08/27"sv).has_value());
|
||||
assert(extract_date("2018/08/27"sv)->year == "2018"sv);
|
||||
assert(extract_date("2018/08/27"sv)->month == "08"sv);
|
||||
assert(extract_date("2018/08/27"sv)->day == "27"sv);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
name: Tests
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
appleclang:
|
||||
strategy:
|
||||
matrix:
|
||||
macos: [12, 13]
|
||||
standard: [17, 20]
|
||||
fail-fast: false
|
||||
name: "AppleClang (MacOS ${{ matrix.macos }}, C++${{ matrix.standard }})"
|
||||
runs-on: macos-${{ matrix.macos }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: c++ -v
|
||||
- run: make CXX=c++ CXX_STANDARD=2a
|
||||
if: ${{ matrix.standard == '20' }}
|
||||
- run: make CXX=c++ CXX_STANDARD=17
|
||||
if: ${{ matrix.standard == '17' }}
|
||||
gcc:
|
||||
strategy:
|
||||
matrix:
|
||||
gcc: [8, 9, 10, 11, 13]
|
||||
standard: [17, 20]
|
||||
fail-fast: false
|
||||
name: "GCC ${{ matrix.gcc }} (C++${{ matrix.standard }})"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: "Install GCC"
|
||||
uses: egor-tensin/setup-gcc@v1
|
||||
with:
|
||||
version: ${{ matrix.gcc }}
|
||||
- uses: actions/checkout@v2
|
||||
- run: c++ -v
|
||||
- run: make CXX=c++ CXX_STANDARD=2a
|
||||
if: ${{ matrix.standard == '20' }}
|
||||
- run: make CXX=c++ CXX_STANDARD=17
|
||||
if: ${{ matrix.gcc < '9' && matrix.standard == '17' }}
|
||||
- run: make CXX=c++ CXX_STANDARD=17 CXXFLAGS=-DCTRE_ENABLE_LITERALS PEDANTIC=""
|
||||
if: ${{ matrix.gcc >= '9' && matrix.standard == '17' }}
|
||||
clang:
|
||||
strategy:
|
||||
matrix:
|
||||
clang: [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
|
||||
stdlib: ["libc++", "libstdc++"]
|
||||
standard: [17, 20]
|
||||
fail-fast: false
|
||||
name: "Clang ${{ matrix.clang }} (C++${{ matrix.standard }}, ${{ matrix.stdlib }})"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: "Install Clang"
|
||||
uses: egor-tensin/setup-clang@v1
|
||||
with:
|
||||
version: ${{ matrix.clang }}
|
||||
- name: "Install libc++"
|
||||
if: ${{ matrix.stdlib == 'libc++' }}
|
||||
run: sudo apt-get install libc++abi-${{ matrix.clang }}-dev libc++1-${{ matrix.clang }} libc++-${{ matrix.clang }}-dev
|
||||
- uses: actions/checkout@v2
|
||||
- run: c++ -v
|
||||
- run: make CXX=c++ CXX_STANDARD=2a CXXFLAGS=-stdlib=${{ matrix.stdlib }}
|
||||
if: ${{ matrix.standard == '20' }}
|
||||
- run: make CXX=c++ CXX_STANDARD=17 CXXFLAGS=-stdlib=${{ matrix.stdlib }}
|
||||
if: ${{ matrix.standard == '17' }}
|
||||
msvc:
|
||||
strategy:
|
||||
matrix:
|
||||
version: [14.29, ""]
|
||||
fail-fast: false
|
||||
name: "MSVC ${{ matrix.version }} (C++20)"
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Add MSVC ${{ matrix.version }} to PATH
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
toolset: ${{ matrix.version }}
|
||||
- name: "Install Ninja & CMake"
|
||||
run: choco install ninja cmake
|
||||
- uses: actions/checkout@v2
|
||||
- name: "Configure"
|
||||
run: cmake . -G Ninja -B build -DCTRE_BUILD_TESTS=ON -DCTRE_CXX_STANDARD=20
|
||||
- name: "Build"
|
||||
run: cmake --build build --target ctre-test --verbose
|
|
@ -0,0 +1,22 @@
|
|||
*.o
|
||||
*.d
|
||||
**/*.tmp
|
||||
test
|
||||
result
|
||||
tests/benchmark-exec/*
|
||||
!tests/benchmark-exec/Makefile
|
||||
!tests/benchmark-exec/.gitignore
|
||||
!tests/benchmark-exec/.tm_properties
|
||||
!tests/benchmark-exec/*.cpp
|
||||
!tests/benchmark-exec/*.hpp
|
||||
!tests/benchmark-exec/*.js
|
||||
*.pyc
|
||||
.conan/test_package/build
|
||||
mtent12.txt
|
||||
*.zip
|
||||
tests/benchmark-range/*
|
||||
!tests/benchmark-range/*.cpp
|
||||
!tests/benchmark-range/*.hpp
|
||||
build
|
||||
cmake-build-*/*
|
||||
.idea/*
|
|
@ -0,0 +1,3 @@
|
|||
exclude = "{$exclude,**/*.dSYM,**/*.d,**/*.o,test,*.tmp}"
|
||||
include = "{$include,.gitignore,.github,.travis*,.conan}"
|
||||
excludeInFolderSearch = "{$excludeInFolderSearch,./ctre.hpp}"
|
|
@ -0,0 +1,113 @@
|
|||
language: cpp
|
||||
dist: focal
|
||||
os: linux
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- os: linux
|
||||
language: python
|
||||
python: "3.6"
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- COMPILER=g++-8
|
||||
- CONAN_GCC_VERSIONS=8
|
||||
- CONAN_DOCKER_IMAGE=lasote/conangcc8
|
||||
install:
|
||||
- pip install -U conan conan-package-tools
|
||||
script:
|
||||
- python .conan/build.py
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- COMPILER=g++-8
|
||||
- CXX_STANDARD=17
|
||||
addons:
|
||||
apt:
|
||||
packages: ['g++-8']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- COMPILER=g++-8
|
||||
- CXX_STANDARD=2a
|
||||
addons:
|
||||
apt:
|
||||
packages: ['g++-8']
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- COMPILER=clang++-6.0
|
||||
- CXX_STANDARD=17
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
|
||||
packages: ['g++-8', 'clang-6.0']
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- COMPILER=clang++-6.0
|
||||
- CXX_STANDARD=2a
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
|
||||
packages: ['g++-8', 'clang-6.0']
|
||||
|
||||
# FIXME: don't use GCC10 in 17 mode for tests as they are depending on operator""
|
||||
# - os: linux
|
||||
# compiler: gcc
|
||||
# env:
|
||||
# - COMPILER=g++-10
|
||||
# - CXX_STANDARD=17
|
||||
# addons:
|
||||
# apt:
|
||||
# packages: ['g++-10']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- COMPILER=g++-10
|
||||
- CXX_STANDARD=20
|
||||
addons:
|
||||
apt:
|
||||
packages: ['g++-10']
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10
|
||||
env:
|
||||
- CXX_STANDARD=17
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10
|
||||
env:
|
||||
- CXX_STANDARD=2a
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode11
|
||||
env:
|
||||
- CXX_STANDARD=17
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode11
|
||||
env:
|
||||
- CXX_STANDARD=2a
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode12
|
||||
env:
|
||||
- CXX_STANDARD=17
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode12
|
||||
env:
|
||||
- CXX_STANDARD=2a
|
||||
|
||||
install:
|
||||
- if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi
|
||||
- uname -a
|
||||
- $CXX --version
|
||||
script:
|
||||
- make CXX_STANDARD=$CXX_STANDARD
|
|
@ -0,0 +1,196 @@
|
|||
cmake_minimum_required(VERSION 3.14...3.29)
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.29.20240416")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "0e5b6991-d74f-4b3d-a41c-cf096e0b2508")
|
||||
set(CMAKE_CXX_MODULE_STD 1)
|
||||
endif()
|
||||
|
||||
# When updating to a newer version of CMake, see if we can use the following
|
||||
project(ctre
|
||||
HOMEPAGE_URL "https://compile-time.re"
|
||||
VERSION 3.9.0
|
||||
LANGUAGES CXX)
|
||||
set(PROJECT_DESCRIPTION "Fast compile-time regular expressions with support for matching/searching/capturing during compile-time or runtime.")
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CMakeDependentOption)
|
||||
include(GNUInstallDirs)
|
||||
include(CTest)
|
||||
|
||||
find_program(CTRE_DPKG_BUILDPACKAGE_FOUND dpkg-buildpackage)
|
||||
find_program(CTRE_RPMBUILD_FOUND rpmbuild)
|
||||
|
||||
cmake_dependent_option(CTRE_BUILD_TESTS "Build ctre Tests" ON
|
||||
"BUILD_TESTING;CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
|
||||
cmake_dependent_option(CTRE_BUILD_PACKAGE "Build ctre Packages" ON
|
||||
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
|
||||
cmake_dependent_option(CTRE_BUILD_PACKAGE_DEB
|
||||
"Create DEB Package (${PROJECT_NAME})" ON
|
||||
"CTRE_BUILD_PACKAGE;CTRE_DPKG_BUILDPACKAGE_FOUND" OFF)
|
||||
cmake_dependent_option(CTRE_BUILD_PACKAGE_RPM
|
||||
"Create RPM Package (${PROJECT_NAME})" ON
|
||||
"CTRE_BUILD_PACKAGE;CTRE_RPMBUILD_FOUND" OFF)
|
||||
|
||||
option(CTRE_MODULE "build C++ module" OFF)
|
||||
|
||||
if(CTRE_MODULE)
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.29.20240416")
|
||||
add_library(${PROJECT_NAME})
|
||||
|
||||
target_sources(${PROJECT_NAME} PUBLIC FILE_SET CXX_MODULES TYPE CXX_MODULES FILES ctre.cppm)
|
||||
target_sources(${PROJECT_NAME} PUBLIC FILE_SET HEADERS TYPE HEADERS
|
||||
BASE_DIRS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
FILES
|
||||
include/ctll.hpp
|
||||
include/ctre/functions.hpp
|
||||
include/ctre/utility.hpp
|
||||
include/ctre/utf8.hpp
|
||||
include/ctre/evaluation.hpp
|
||||
include/ctre/starts_with_anchor.hpp
|
||||
include/ctre/pcre_actions.hpp
|
||||
include/ctre/rotate.hpp
|
||||
include/ctre/iterators.hpp
|
||||
include/ctre/literals.hpp
|
||||
include/ctre/return_type.hpp
|
||||
include/ctre/find_captures.hpp
|
||||
include/ctre/id.hpp
|
||||
include/ctre/atoms_characters.hpp
|
||||
include/ctre/actions/mode.inc.hpp
|
||||
include/ctre/actions/characters.inc.hpp
|
||||
include/ctre/actions/class.inc.hpp
|
||||
include/ctre/actions/look.inc.hpp
|
||||
include/ctre/actions/sequence.inc.hpp
|
||||
include/ctre/actions/fusion.inc.hpp
|
||||
include/ctre/actions/asserts.inc.hpp
|
||||
include/ctre/actions/capture.inc.hpp
|
||||
include/ctre/actions/named_class.inc.hpp
|
||||
include/ctre/actions/backreference.inc.hpp
|
||||
include/ctre/actions/options.inc.hpp
|
||||
include/ctre/actions/atomic_group.inc.hpp
|
||||
include/ctre/actions/set.inc.hpp
|
||||
include/ctre/actions/hexdec.inc.hpp
|
||||
include/ctre/actions/repeat.inc.hpp
|
||||
include/ctre/actions/properties.inc.hpp
|
||||
include/ctre/actions/boundaries.inc.hpp
|
||||
include/ctre/operators.hpp
|
||||
include/ctre/pcre.hpp
|
||||
include/ctre/atoms_unicode.hpp
|
||||
include/ctre/range.hpp
|
||||
include/ctre/wrapper.hpp
|
||||
include/ctre/first.hpp
|
||||
include/ctre/flags_and_modes.hpp
|
||||
include/ctre/atoms.hpp
|
||||
include/unicode-db.hpp
|
||||
include/unicode-db/unicode_interface.hpp
|
||||
include/unicode-db/unicode-db.hpp
|
||||
include/ctll/parser.hpp
|
||||
include/ctll/actions.hpp
|
||||
include/ctll/fixed_string.hpp
|
||||
include/ctll/list.hpp
|
||||
include/ctll/utilities.hpp
|
||||
include/ctll/grammars.hpp
|
||||
include/ctre.hpp
|
||||
include/ctre-unicode.hpp
|
||||
)
|
||||
|
||||
# we are using `import std;`
|
||||
if (NOT DEFINED CTRE_CXX_STANDARD OR CTRE_CXX_STANDARD LESS 23)
|
||||
set(CTRE_CXX_STANDARD 23)
|
||||
endif()
|
||||
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_${CTRE_CXX_STANDARD})
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets
|
||||
FILE_SET CXX_MODULES DESTINATION "${CMAKE_INSTALL_LIBDIR}/cxx/${PROJECT_NAME}"
|
||||
FILE_SET HEADERS DESTINATION "include")
|
||||
else()
|
||||
message(FATAL_ERROR "unsupported cmake for c++ modules")
|
||||
endif()
|
||||
else()
|
||||
add_library(${PROJECT_NAME} INTERFACE)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
if (NOT CTRE_CXX_STANDARD)
|
||||
set(CTRE_CXX_STANDARD 20)
|
||||
endif()
|
||||
|
||||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_${CTRE_CXX_STANDARD})
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_SCAN_FOR_MODULES 0)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets)
|
||||
install(DIRECTORY include/ DESTINATION include
|
||||
FILES_MATCHING PATTERN *.hpp)
|
||||
endif()
|
||||
|
||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
|
||||
if (NOT EXISTS "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake.in")
|
||||
file(WRITE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake.in [[
|
||||
@PACKAGE_INIT@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
|
||||
]])
|
||||
endif()
|
||||
|
||||
configure_package_config_file(
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake.in"
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||
|
||||
write_basic_package_version_file(ctre-config-version.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
install(EXPORT ${PROJECT_NAME}-targets
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
NAMESPACE ${PROJECT_NAME}::)
|
||||
install(
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake"
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
|
||||
if(CTRE_BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (NOT CTRE_BUILD_PACKAGE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND source-generators TBZ2 TGZ TXZ ZIP)
|
||||
|
||||
if (CTRE_BUILD_PACKAGE_DEB)
|
||||
list(APPEND binary-generators "DEB")
|
||||
endif()
|
||||
|
||||
if (CTRE_BUILD_PACKAGE_RPM)
|
||||
list(APPEND binary-generators "RPM")
|
||||
endif()
|
||||
|
||||
set(CPACK_SOURCE_GENERATOR ${source-generators})
|
||||
set(CPACK_GENERATOR ${binary-generators})
|
||||
|
||||
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}")
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Hana Dusíková")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}")
|
||||
set(CPACK_DEBIAN_PACKAGE_NAME "lib${PROJECT_NAME}-dev")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_NAME "lib${PROJECT_NAME}-devel")
|
||||
|
||||
set(PKG_CONFIG_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/packaging/pkgconfig.pc.in" "${PKG_CONFIG_FILE_NAME}" @ONLY)
|
||||
install(FILES "${PKG_CONFIG_FILE_NAME}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
|
||||
)
|
||||
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES /.git/ /build/ .gitignore .DS_Store)
|
||||
|
||||
include(CPack)
|
|
@ -0,0 +1,218 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
--- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
|
@ -0,0 +1,92 @@
|
|||
.PHONY: default all clean grammar compare single-header single-header/ctre.hpp single-header/ctre-unicode.hpp single-header/unicode-db.hpp
|
||||
|
||||
default: all
|
||||
|
||||
TARGETS := $(wildcard tests/benchmark-exec/*.cpp)
|
||||
IGNORE := $(wildcard tests/benchmark/*.cpp) $(wildcard tests/benchmark-exec/*.cpp)
|
||||
|
||||
DESATOMAT := /bin/false
|
||||
|
||||
CXX_STANDARD := 20
|
||||
|
||||
PYTHON := python3.9
|
||||
|
||||
PEDANTIC:=-pedantic
|
||||
|
||||
override CXXFLAGS := $(CXXFLAGS) -std=c++$(CXX_STANDARD) -Iinclude -O3 $(PEDANTIC) -Wall -Wextra -Werror -Wconversion
|
||||
LDFLAGS :=
|
||||
|
||||
TESTS := $(wildcard tests/*.cpp) $(wildcard tests/benchmark/*.cpp)
|
||||
TRUE_TARGETS := $(TARGETS:%.cpp=%)
|
||||
override TRUE_TARGETS := $(filter-out $(IGNORE:%.cpp=%), $(TRUE_TARGETS))
|
||||
OBJECTS := $(TARGETS:%.cpp=%.o) $(TESTS:%.cpp=%.o)
|
||||
override OBJECTS := $(filter-out $(IGNORE:%.cpp=%.o),$(OBJECTS))
|
||||
DEPEDENCY_FILES := $(OBJECTS:%.o=%.d)
|
||||
|
||||
all: $(TRUE_TARGETS) $(OBJECTS)
|
||||
|
||||
list:
|
||||
echo $(SUPPORTED_CPP20)
|
||||
|
||||
$(TRUE_TARGETS): %: %.o
|
||||
$(CXX) $< $(LDFLAGS) -o $@
|
||||
|
||||
$(OBJECTS): %.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) -MMD -c $< -o $@
|
||||
|
||||
-include $(DEPEDENCY_FILES)
|
||||
|
||||
benchmark:
|
||||
@$(MAKE) clean
|
||||
@$(MAKE) IGNORE=""
|
||||
|
||||
benchmark-clean:
|
||||
@$(MAKE) IGNORE="" clean
|
||||
|
||||
clean:
|
||||
rm -f $(TRUE_TARGETS) $(OBJECTS) $(DEPEDENCY_FILES) mtent12.txt mtent12.zip
|
||||
|
||||
grammar: include/ctre/pcre.hpp
|
||||
|
||||
regrammar:
|
||||
@rm -f include/ctre/pcre.hpp
|
||||
@$(MAKE) grammar
|
||||
|
||||
include/ctre/pcre.hpp: include/ctre/pcre.gram
|
||||
@echo "LL1q $<"
|
||||
@$(DESATOMAT) --ll --q --input=include/ctre/pcre.gram --output=include/ctre/ --generator=cpp_ctll_v2 --cfg:fname=pcre.hpp --cfg:namespace=ctre --cfg:guard=CTRE__PCRE__HPP --cfg:grammar_name=pcre
|
||||
|
||||
mtent12.zip:
|
||||
curl -s http://www.gutenberg.org/files/3200/old/mtent12.zip -o mtent12.zip
|
||||
|
||||
mtent12.txt: mtent12.zip
|
||||
unzip -o mtent12.zip
|
||||
touch mtent12.txt
|
||||
|
||||
single-header: single-header/ctre.hpp single-header/ctre-unicode.hpp single-header/unicode-db.hpp
|
||||
|
||||
single-header/unicode-db.hpp: include/unicode-db/unicode-db.hpp
|
||||
cp $+ $@
|
||||
|
||||
single-header/ctre.hpp:
|
||||
${PYTHON} -m quom include/ctre.hpp ctre.hpp.tmp
|
||||
echo "/*" > single-header/ctre.hpp
|
||||
cat LICENSE >> single-header/ctre.hpp
|
||||
echo "*/" >> single-header/ctre.hpp
|
||||
cat ctre.hpp.tmp >> single-header/ctre.hpp
|
||||
rm ctre.hpp.tmp
|
||||
|
||||
single-header/ctre-unicode.hpp:
|
||||
${PYTHON} -m quom include/ctre-unicode.hpp ctre-unicode.hpp.tmp
|
||||
echo "/*" > single-header/ctre-unicode.hpp
|
||||
cat LICENSE >> single-header/ctre-unicode.hpp
|
||||
echo "*/" >> single-header/ctre-unicode.hpp
|
||||
cat ctre-unicode.hpp.tmp >> single-header/ctre-unicode.hpp
|
||||
rm ctre-unicode.hpp.tmp
|
||||
|
||||
REPEAT:=10
|
||||
|
||||
compare: mtent12.txt
|
||||
$(CXX) $(CXXFLAGS) -MMD -march=native -DPATTERN="\"(${PATTERN})\"" -c tests/benchmark-range/measurement.cpp -o tests/benchmark-range/measurement.o
|
||||
$(CXX) tests/benchmark-range/measurement.o -lboost_regex -lpcre2-8 -lre2 -o tests/benchmark-range/measurement
|
||||
tests/benchmark-range/measurement all mtent12.txt ${REPEAT}
|
|
@ -0,0 +1,24 @@
|
|||
# Unsupported PCRE constructs
|
||||
|
||||
* `\0dd` `\ddd` `\0{dd...}` octal numbers
|
||||
* `\Q...\E` quoting
|
||||
* `\cx` control characters
|
||||
* `\C` data unit
|
||||
* `\h` `\H` horizontal character classes
|
||||
* `\v` `\V` vertical character classes
|
||||
* `\p{xx}` `\P{xx}` character properties
|
||||
* `\X` unicode grapheme cluster
|
||||
* boundaries other than `^$`
|
||||
* atomic groups
|
||||
* comments
|
||||
* options/modes
|
||||
* subroutines
|
||||
* conditional patterns
|
||||
* callouts
|
||||
* match point reset `\K`
|
||||
|
||||
|
||||
# Other unsupported "things"
|
||||
* `[[.hyphen.]]` named characters
|
||||
* `[[=M=]]` whatever this is
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
# Compile time regular expressions v3
|
||||
|
||||
[](https://travis-ci.org/hanickadot/compile-time-regular-expressions)
|
||||
|
||||
Fast compile-time regular expressions with support for matching/searching/capturing during compile-time or runtime.
|
||||
|
||||
You can use the single header version from directory `single-header`. This header can be regenerated with `make single-header`. If you are using cmake, you can add this directory as subdirectory and link to target `ctre`.
|
||||
|
||||
More info at [compile-time.re](https://compile-time.re/)
|
||||
|
||||
## What this library can do
|
||||
|
||||
```c++
|
||||
ctre::match<"REGEX">(subject); // C++20
|
||||
"REGEX"_ctre.match(subject); // C++17 + N3599 extension
|
||||
```
|
||||
|
||||
* Matching
|
||||
* Searching (`search` or `starts_with`)
|
||||
* Capturing content (named captures are supported too, but only with syntax `(?<name>...)`)
|
||||
* Back-Reference (\g{N} syntax, and \1...\9 syntax too)
|
||||
* Multiline support (with `multi_`) functions
|
||||
* Unicode properties and UTF-8 support
|
||||
|
||||
The library is implementing most of the PCRE syntax with a few exceptions:
|
||||
|
||||
* callouts
|
||||
* comments
|
||||
* conditional patterns
|
||||
* control characters (`\cX`)
|
||||
* match point reset (`\K`)
|
||||
* named characters
|
||||
* octal numbers
|
||||
* options / modes
|
||||
* subroutines
|
||||
* unicode grapheme cluster (`\X`)
|
||||
|
||||
More documentation on [pcre.org](https://www.pcre.org/current/doc/html/pcre2syntax.html).
|
||||
|
||||
### Unknown character escape behaviour
|
||||
|
||||
Not all escaped characters are automatically inserted as self, behaviour of the library is escaped characters are with special meaning, unknown escaped character is a syntax error.
|
||||
|
||||
Explicitly allowed character escapes which insert only the character are:
|
||||
|
||||
```\-\"\<\>```
|
||||
|
||||
## Basic API
|
||||
|
||||
This is approximated API specification from a user perspective (omitting `constexpr` and `noexcept` which are everywhere, and using C++20 syntax even the API is C++17 compatible):
|
||||
```c++
|
||||
// look if whole input matches the regex:
|
||||
template <fixed_string regex> auto ctre::match(auto Range &&) -> regex_results;
|
||||
template <fixed_string regex> auto ctre::match(auto First &&, auto Last &&) -> regex_results;
|
||||
|
||||
// look if input contains match somewhere inside of itself:
|
||||
template <fixed_string regex> auto ctre::search(auto Range &&) -> regex_results;
|
||||
template <fixed_string regex> auto ctre::search(auto First &&, auto Last &&) -> regex_results;
|
||||
|
||||
// check if input starts with match (but doesn't need to match everything):
|
||||
template <fixed_string regex> auto ctre::starts_with(auto Range &&) -> regex_results;
|
||||
template <fixed_string regex> auto ctre::starts_with(auto First &&, auto Last &&) -> regex_results;
|
||||
|
||||
// result type is deconstructible into a structured bindings
|
||||
template <...> struct regex_results {
|
||||
operator bool() const; // if it's a match
|
||||
auto to_view() const -> std::string_view; // also view()
|
||||
auto to_string() const -> std::string; // also str()
|
||||
operator std::string_view() const; // also supports all char variants
|
||||
explicit operator std::string() const;
|
||||
|
||||
// also size(), begin(), end(), data()
|
||||
|
||||
size_t count() const; // number of captures
|
||||
template <size_t Id> const captured_content & get() const; // provide specific capture, whole regex_results is implicit capture 0
|
||||
};
|
||||
```
|
||||
|
||||
### Range outputing API
|
||||
|
||||
```c++
|
||||
// search for regex in input and return each occurence, ignoring rest:
|
||||
template <fixed_string regex> auto ctre::range(auto Range &&) -> range of regex_result;
|
||||
template <fixed_string regex> auto ctre::range(auto First &&, auto Last &&) -> range of regex_result;
|
||||
|
||||
// return range of each match, stopping at something which can't be matched
|
||||
template <fixed_string regex> auto ctre::tokenize(auto Range &&) -> range of regex_result;
|
||||
template <fixed_string regex> auto ctre::tokenize(auto First &&, auto Last &&) -> range of regex_result;
|
||||
|
||||
// return parts of the input splited by the regex, returning it as part of content of the implicit zero capture (other captures are not changed, you can use it to access how the values were splitted):
|
||||
template <fixed_string regex> auto ctre::split(auto Range &&) -> regex_result;
|
||||
template <fixed_string regex> auto ctre::split(auto First &&, auto Last &&) -> range of regex_result;
|
||||
```
|
||||
|
||||
### Functors
|
||||
|
||||
All the functions (`ctre::match`, `ctre::search`, `ctre::starts_with`, `ctre::range`, `ctre::tokenize`, `ctre::split`) are functors and can be used without parenthesis:
|
||||
|
||||
```c++
|
||||
auto matcher = ctre::match<"regex">;
|
||||
if (matcher(input)) ...
|
||||
```
|
||||
|
||||
### Possible subjects (inputs)
|
||||
|
||||
* `std::string`-like objects (`std::string_view` or your own string if it's providing `begin`/`end` functions with forward iterators)
|
||||
* pairs of forward iterators
|
||||
|
||||
### Unicode support
|
||||
|
||||
To enable you need to include:
|
||||
* `<ctre-unicode.hpp>`
|
||||
* or `<ctre.hpp>` and `<unicode-db.hpp>`
|
||||
|
||||
Otherwise you will get missing symbols if you try to use the unicode support without enabling it.
|
||||
|
||||
## Supported compilers
|
||||
|
||||
* clang 7.0+ (template UDL, C++17 syntax)
|
||||
* xcode clang 10.0+ (template UDL, C++17 syntax)
|
||||
* clang 12.0+ (C++17 syntax, C++20 cNTTP syntax)
|
||||
* gcc 8.0+ (template UDL, C++17 syntax)
|
||||
* gcc 9.0+ (C++17 & C++20 cNTTP syntax)
|
||||
* MSVC 14.29+ (Visual Studio 16.11+) (C++20)
|
||||
|
||||
### Template UDL syntax
|
||||
|
||||
The compiler must support extension N3599, for example as GNU extension in gcc (not in GCC 9.1+) and clang.
|
||||
|
||||
```c++
|
||||
constexpr auto match(std::string_view sv) noexcept {
|
||||
using namespace ctre::literals;
|
||||
return "h.*"_ctre.match(sv);
|
||||
}
|
||||
```
|
||||
|
||||
If you need extension N3599 in GCC 9.1+, you can't use -pedantic. Also, you need to define macro `CTRE_ENABLE_LITERALS`.
|
||||
|
||||
### C++17 syntax
|
||||
|
||||
You can provide a pattern as a `constexpr ctll::fixed_string` variable.
|
||||
|
||||
```c++
|
||||
static constexpr auto pattern = ctll::fixed_string{ "h.*" };
|
||||
|
||||
constexpr auto match(std::string_view sv) noexcept {
|
||||
return ctre::match<pattern>(sv);
|
||||
}
|
||||
```
|
||||
|
||||
(this is tested in MSVC 15.8.8)
|
||||
|
||||
### C++20 syntax
|
||||
|
||||
Currently, the only compiler which supports cNTTP syntax `ctre::match<PATTERN>(subject)` is GCC 9+.
|
||||
|
||||
```c++
|
||||
constexpr auto match(std::string_view sv) noexcept {
|
||||
return ctre::match<"h.*">(sv);
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Extracting number from input
|
||||
|
||||
```c++
|
||||
std::optional<std::string_view> extract_number(std::string_view s) noexcept {
|
||||
if (auto m = ctre::match<"[a-z]+([0-9]+)">(s)) {
|
||||
return m.get<1>().to_view();
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[link to compiler explorer](https://gcc.godbolt.org/z/5U67_e)
|
||||
|
||||
### Extracting values from date
|
||||
|
||||
```c++
|
||||
struct date { std::string_view year; std::string_view month; std::string_view day; };
|
||||
|
||||
std::optional<date> extract_date(std::string_view s) noexcept {
|
||||
using namespace ctre::literals;
|
||||
if (auto [whole, year, month, day] = ctre::match<"(\\d{4})/(\\d{1,2})/(\\d{1,2})">(s); whole) {
|
||||
return date{year, month, day};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
//static_assert(extract_date("2018/08/27"sv).has_value());
|
||||
//static_assert((*extract_date("2018/08/27"sv)).year == "2018"sv);
|
||||
//static_assert((*extract_date("2018/08/27"sv)).month == "08"sv);
|
||||
//static_assert((*extract_date("2018/08/27"sv)).day == "27"sv);
|
||||
```
|
||||
|
||||
[link to compiler explorer](https://gcc.godbolt.org/z/x64CVp)
|
||||
|
||||
### Using captures
|
||||
|
||||
```c++
|
||||
auto result = ctre::match<"(?<year>\\d{4})/(?<month>\\d{1,2})/(?<day>\\d{1,2})">(s);
|
||||
return date{result.get<"year">(), result.get<"month">, result.get<"day">};
|
||||
|
||||
// or in C++ emulation, but the object must have a linkage
|
||||
static constexpr ctll::fixed_string year = "year";
|
||||
static constexpr ctll::fixed_string month = "month";
|
||||
static constexpr ctll::fixed_string day = "day";
|
||||
return date{result.get<year>(), result.get<month>, result.get<day>};
|
||||
|
||||
// or use numbered access
|
||||
// capture 0 is the whole match
|
||||
return date{result.get<1>(), result.get<2>, result.get<3>};
|
||||
```
|
||||
|
||||
### Lexer
|
||||
|
||||
```c++
|
||||
enum class type {
|
||||
unknown, identifier, number
|
||||
};
|
||||
|
||||
struct lex_item {
|
||||
type t;
|
||||
std::string_view c;
|
||||
};
|
||||
|
||||
std::optional<lex_item> lexer(std::string_view v) noexcept {
|
||||
if (auto [m,id,num] = ctre::match<"([a-z]+)|([0-9]+)">(v); m) {
|
||||
if (id) {
|
||||
return lex_item{type::identifier, id};
|
||||
} else if (num) {
|
||||
return lex_item{type::number, num};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
```
|
||||
|
||||
[link to compiler explorer](https://gcc.godbolt.org/z/PKTiCC)
|
||||
|
||||
### Range over input
|
||||
|
||||
This support is preliminary, probably the API will be changed.
|
||||
|
||||
```c++
|
||||
auto input = "123,456,768"sv;
|
||||
|
||||
for (auto match: ctre::range<"([0-9]+),?">(input)) {
|
||||
std::cout << std::string_view{match.get<0>()} << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
### Unicode
|
||||
|
||||
```c++
|
||||
#include <ctre-unicode.hpp>
|
||||
#include <iostream>
|
||||
// needed if you want to output to the terminal
|
||||
std::string_view cast_from_unicode(std::u8string_view input) noexcept {
|
||||
return std::string_view(reinterpret_cast<const char *>(input.data()), input.size());
|
||||
}
|
||||
int main()
|
||||
{
|
||||
using namespace std::literals;
|
||||
std::u8string_view original = u8"Tu es un génie"sv;
|
||||
|
||||
for (auto match : ctre::range<"\\p{Letter}+">(original))
|
||||
std::cout << cast_from_unicode(match) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
[link to compiler explorer](https://godbolt.org/z/erTshe6sz)
|
||||
|
||||
|
||||
## Installing ctre using vcpkg
|
||||
|
||||
You can download and install ctre using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
./vcpkg install ctre
|
||||
```
|
||||
|
||||
The ctre port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
## Running tests (for developers)
|
||||
|
||||
Just run `make` in root of this project.
|
|
@ -0,0 +1,20 @@
|
|||
//--------- ABCD|DEFGH|EFGHI|A{4,}
|
||||
egrep 0m49.353s
|
||||
CTRE 0m10.093s
|
||||
PCRE 0m12.515s
|
||||
std::regex 21m9.309s
|
||||
//--------- [0-9a-fA-F]{8,16}
|
||||
egrep 0m32.256s
|
||||
CTRE 0m14.197s
|
||||
PCRE 0m17.832s
|
||||
std::regex 2m34.505s
|
||||
//--------- ^([0-9]{4,16})?[aA]
|
||||
egrep 0m12.880s
|
||||
CTRE 0m7.596s
|
||||
PCRE 0m6.590s
|
||||
std::regex 7m54.793s
|
||||
//--------- ([aAbB]{4,}|[xXyY]{4,}|[1234]{4,})0
|
||||
egrep 1m56.412s
|
||||
CTRE 0m59.864s
|
||||
PCRE 0m43.486s
|
||||
std::regex 27m35.004s
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from conans import ConanFile
|
||||
|
||||
|
||||
class CtreConan(ConanFile):
|
||||
name = "CTRE"
|
||||
license = "Apache 2.0 with LLVM Exception"
|
||||
url = "https://github.com/hanickadot/compile-time-regular-expressions"
|
||||
author = "Hana Dusíková (ctre@hanicka.net)"
|
||||
description = "Compile Time Regular Expression for C++17/20"
|
||||
homepage = "https://github.com/hanickadot/compile-time-regular-expressions"
|
||||
no_copy_source = True
|
||||
scm = {
|
||||
"type": "git",
|
||||
"url": "auto",
|
||||
"revision": "auto"
|
||||
}
|
||||
|
||||
def package(self):
|
||||
self.copy("LICENSE", "licenses")
|
||||
self.copy("*.hpp")
|
||||
|
||||
def package_id(self):
|
||||
self.info.header_only()
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
module;
|
||||
|
||||
#ifdef _MSVC_LANG
|
||||
#pragma warning( disable : 5202 )
|
||||
#endif
|
||||
|
||||
import std;
|
||||
|
||||
export module ctre;
|
||||
|
||||
#define CTRE_IN_A_MODULE
|
||||
#define CTLL_IN_A_MODULE
|
||||
#define UNICODE_DB_IN_A_MODULE
|
||||
|
||||
using std::int16_t;
|
||||
using std::int32_t;
|
||||
using std::int64_t;
|
||||
using std::int8_t;
|
||||
using std::size_t;
|
||||
using std::uint16_t;
|
||||
using std::uint32_t;
|
||||
using std::uint64_t;
|
||||
using std::uint8_t;
|
||||
|
||||
#include "ctre.hpp"
|
||||
#include "unicode-db.hpp"
|
|
@ -0,0 +1,100 @@
|
|||
API
|
||||
===
|
||||
|
||||
.. class:: ctll::fixed_string
|
||||
|
||||
A compile-time fixed string.
|
||||
|
||||
Example: ::
|
||||
|
||||
static constexpr auto pattern = ctll::fixed_string{ "h.*" };
|
||||
|
||||
constexpr auto match(std::string_view sv) noexcept {
|
||||
return ctre::match<pattern>(sv);
|
||||
}
|
||||
|
||||
.. class:: template<class Iterator, class... Captures> ctre::regex_results
|
||||
|
||||
.. type:: char_type = typename std::iterator_traits<Iterator>::value_type
|
||||
|
||||
The character type used by the ``Iterator``.
|
||||
|
||||
.. function:: template<size_t Id> constexpr captured_content<Id, void>::storage<Iterator> get()
|
||||
template<class Name> constexpr captured_content<deduced, Name>::storage<Iterator> get()
|
||||
template<ctll::fixed_string Name> constexpr captured_content<deduced, Name>::storage<Iterator> get()
|
||||
|
||||
Returns the capture specified by ``Id`` or ``Name``. ID ``0`` is the full match, ID ``1`` is the first capture group, ID ``2`` is the second, etc.
|
||||
Named groups are specified using ``(?<name>)``.
|
||||
|
||||
Example: ::
|
||||
|
||||
if (auto m = ctre::match<"(?<chars>[a-z]+)([0-9]+)">("abc123")) {
|
||||
m.get<"chars">(); //abc
|
||||
m.get<2>(); //123
|
||||
}
|
||||
|
||||
.. function:: constexpr size_t size()
|
||||
|
||||
Returns the number of captures in this result object.
|
||||
|
||||
.. function:: constexpr operator bool() const noexcept
|
||||
|
||||
Returns whether the match was successful.
|
||||
|
||||
.. function:: constexpr operator std::basic_string_view<char_type>() const noexcept
|
||||
constexpr std::basic_string_view<char_type> to_view() const noexcept
|
||||
constexpr std::basic_string_view<char_type> view() const noexcept
|
||||
|
||||
Converts the match to a string view.
|
||||
|
||||
.. function:: constexpr explicit operator std::basic_string<char_type>() const noexcept
|
||||
constexpr std::basic_string<char_type> to_string() const noexcept
|
||||
constexpr std::basic_string<char_type> str() const noexcept
|
||||
|
||||
Converts the match to a string view.
|
||||
|
||||
.. class:: template<size_t Id, typename Name = void> captured_content
|
||||
|
||||
.. class:: template <typename Iterator> storage
|
||||
|
||||
.. function:: constexpr auto begin() const noexcept
|
||||
constexpr auto end() const noexcept
|
||||
|
||||
Returns the begin or end iterator for the captured content.
|
||||
|
||||
.. function:: constexpr operator bool() const noexcept
|
||||
|
||||
Returns whether the match was successful.
|
||||
|
||||
.. function:: constexpr auto size() const noexcept
|
||||
|
||||
Returns the number of characters in the capture.
|
||||
|
||||
.. function:: constexpr operator std::basic_string_view<char_type>() const noexcept
|
||||
constexpr std::basic_string_view<char_type> to_view() const noexcept
|
||||
constexpr std::basic_string_view<char_type> view() const noexcept
|
||||
|
||||
Converts the capture to a string view.
|
||||
|
||||
.. function:: constexpr explicit operator std::basic_string<char_type>() const noexcept
|
||||
constexpr std::basic_string<char_type> to_string() const noexcept
|
||||
constexpr std::basic_string<char_type> str() const noexcept
|
||||
|
||||
Converts the capture to a string view.
|
||||
|
||||
.. function:: constexpr static size_t get_id() noexcept
|
||||
|
||||
Returns ``Id``
|
||||
|
||||
.. function:: template<auto & RE, class... Args> constexpr ctre::regex_results<deduced> match(Args&&... args)
|
||||
template<ctll::fixed_string RE, class... Args> constexpr ctre::regex_results<deduced> match(Args&&... args)
|
||||
|
||||
Matches ``RE`` against the whole input.
|
||||
``Args...`` must be either a string-like object with ``begin`` and ``end`` member functions, or a pair of forward iterators.
|
||||
|
||||
.. function:: template<auto & RE, class... Args> constexpr ctre::regex_results<deduced> search(Args&&... args)
|
||||
template<ctll::fixed_string RE, class... Args> constexpr ctre::regex_results<deduced> search(Args&&... args)
|
||||
|
||||
Searches for a match somewhere within the input.
|
||||
``Args...`` must be either a string-like object with ``begin`` and ``end`` member functions, or a pair of forward iterators.
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'ctre'
|
||||
copyright = '2019, Hana Dusikova'
|
||||
author = 'Hana Dusikova'
|
||||
master_doc = 'index'
|
||||
primary_domain = 'cpp'
|
||||
highlight_language = 'cpp'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
|
@ -0,0 +1,77 @@
|
|||
Examples
|
||||
========
|
||||
|
||||
Extracting a number from input
|
||||
------------------------------
|
||||
::
|
||||
|
||||
std::optional<std::string_view> extract_number(std::string_view s) noexcept {
|
||||
if (auto m = ctre::match<"[a-z]+([0-9]+)">(s)) {
|
||||
return m.get<1>().to_view();
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
`link to compiler explorer <https://gcc.godbolt.org/z/5U67_e>`_
|
||||
|
||||
Extracting values from date
|
||||
---------------------------
|
||||
::
|
||||
|
||||
|
||||
struct date { std::string_view year; std::string_view month; std::string_view day; };
|
||||
std::optional<date> extract_date(std::string_view s) noexcept {
|
||||
using namespace ctre::literals;
|
||||
if (auto [whole, year, month, day] = ctre::match<"(\\d{4})/(\\d{1,2})/(\\d{1,2})">(s); whole) {
|
||||
return date{year, month, day};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
//static_assert(extract_date("2018/08/27"sv).has_value());
|
||||
//static_assert((*extract_date("2018/08/27"sv)).year == "2018"sv);
|
||||
//static_assert((*extract_date("2018/08/27"sv)).month == "08"sv);
|
||||
//static_assert((*extract_date("2018/08/27"sv)).day == "27"sv);
|
||||
|
||||
`link to compiler explorer <https://gcc.godbolt.org/z/x64CVp>`_
|
||||
|
||||
Lexer
|
||||
-----
|
||||
::
|
||||
|
||||
enum class type {
|
||||
unknown, identifier, number
|
||||
};
|
||||
|
||||
struct lex_item {
|
||||
type t;
|
||||
std::string_view c;
|
||||
};
|
||||
|
||||
std::optional<lex_item> lexer(std::string_view v) noexcept {
|
||||
if (auto [m,id,num] = ctre::match<"([a-z]+)|([0-9]+)">(v); m) {
|
||||
if (id) {
|
||||
return lex_item{type::identifier, id};
|
||||
} else if (num) {
|
||||
return lex_item{type::number, num};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
`link to compiler explorer <https://gcc.godbolt.org/z/PKTiCC>`_
|
||||
|
||||
Range over input
|
||||
----------------
|
||||
|
||||
This support is preliminary and probably the API will be changed.
|
||||
|
||||
::
|
||||
|
||||
auto input = "123,456,768"sv;
|
||||
|
||||
for (auto match: ctre::range<"([0-9]+),?">(input)) {
|
||||
std::cout << std::string_view{match.get<0>()} << "\n";
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
ctre
|
||||
====
|
||||
|
||||
A compile-time (almost) PCRE-compatible regular expression matcher for C++.
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
Fast compile-time regular expressions with support for matching/searching/capturing at compile-time or runtime. ::
|
||||
|
||||
ctre::match<"REGEX">(subject); // C++20
|
||||
"REGEX"_ctre.match(subject); // C++17 + N3599 extension
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
api
|
||||
examples
|
||||
regex_syntax
|
||||
|
||||
Supported compilers
|
||||
===================
|
||||
|
||||
- clang 6.0+ (template UDL, C++17 syntax)
|
||||
- xcode clang 10.0+ (template UDL, C++17 syntax)
|
||||
- gcc 7.4+ (template UDL, C++17 syntax)
|
||||
- gcc 9.0+ (C++17 & C++20 cNTTP syntax)
|
||||
- MSVC 15.8.8+ (C++17 syntax only)
|
||||
|
||||
Basic Usage
|
||||
===========
|
||||
|
||||
Template UDL syntax
|
||||
-------------------
|
||||
|
||||
Compiler must support N3599 extension, as GNU extension in gcc (not in GCC 9.1+) and clang. ::
|
||||
|
||||
constexpr auto match(std::string_view sv) noexcept {
|
||||
using namespace ctre::literals;
|
||||
return "h.*"_ctre.match(sv);
|
||||
}
|
||||
|
||||
If you need N3599 extension in GCC 9.1+ you can't use -pedantic mode and define the macro ``CTRE_ENABLE_LITERALS``.
|
||||
|
||||
C++17 syntax
|
||||
------------
|
||||
|
||||
You can provide pattern as a constexpr ``ctll::fixed_string variable``. ::
|
||||
|
||||
static constexpr auto pattern = ctll::fixed_string{ "h.*" };
|
||||
|
||||
constexpr auto match(std::string_view sv) noexcept {
|
||||
return ctre::match<pattern>(sv);
|
||||
}
|
||||
|
||||
(this is tested in MSVC 15.8.8)
|
||||
|
||||
C++20 syntax
|
||||
------------
|
||||
|
||||
Currently only compiler which supports cNTTP syntax ``ctre::match<PATTERN>(subject)`` is GCC 9+. ::
|
||||
|
||||
constexpr auto match(std::string_view sv) noexcept {
|
||||
return ctre::match<"h.*">(sv);
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
Regex Syntax
|
||||
============
|
||||
|
||||
The library supports most of the `PCRE <pcre.org>`_ syntax with a few exceptions:
|
||||
|
||||
- callouts
|
||||
- comments
|
||||
- conditional patterns
|
||||
- control characters (\\cX)
|
||||
- horizontal / vertical character classes (\\h\\H\\v\\V)
|
||||
- match point reset (\\K)
|
||||
- named characters
|
||||
- octal numbers
|
||||
- options / modes
|
||||
- subroutines
|
||||
- unicode grapheme cluster (\\X)
|
||||
|
||||
TODO more detailed regex information
|
|
@ -0,0 +1,15 @@
|
|||
#include <ctre.hpp>
|
||||
#include <optional>
|
||||
#include <iostream>
|
||||
|
||||
std::string match(std::string_view sv) {
|
||||
if (auto match = ctre::match<"[a-z]+">(sv); match) {
|
||||
return match.to_string();
|
||||
} else {
|
||||
return "not_match";
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << match("hello") << "\n";
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//--------- ABCD|DEFGH|EFGHI|A{4,}
|
||||
egrep 0m50.036s
|
||||
CTRE 0m3.982s
|
||||
PCRE 0m8.621s
|
||||
std::regex 0m55.058s
|
||||
//--------- [0-9a-fA-F]{8,16}
|
||||
egrep 0m32.361s
|
||||
CTRE 0m4.291s
|
||||
PCRE 0m13.958s
|
||||
std::regex 0m18.179s
|
||||
//--------- ^([0-9]{4,16})?[aA]
|
||||
egrep 0m12.819s
|
||||
CTRE 0m2.844s
|
||||
PCRE 0m2.614s
|
||||
std::regex 0m22.876s
|
||||
//--------- ([aAbB]{4,}|[xXyY]{4,}|[1234]{4,})0
|
||||
egrep 1m45.696s
|
||||
CTRE 0m7.623s
|
||||
PCRE 0m39.808s
|
||||
std::regex 1m2.799s
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef CTRE_V2__CTLL__HPP
|
||||
#define CTRE_V2__CTLL__HPP
|
||||
|
||||
#include "ctll/parser.hpp"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef CTLL__ACTIONS__HPP
|
||||
#define CTLL__ACTIONS__HPP
|
||||
|
||||
namespace ctll {
|
||||
struct empty_subject { };
|
||||
|
||||
struct empty_actions {
|
||||
// dummy operator so using Actions::operator() later will not give error
|
||||
template <typename Action, typename InputSymbol, typename Subject> static constexpr auto apply(Action, InputSymbol, Subject subject) {
|
||||
return subject;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Actions> struct identity: public Actions {
|
||||
using Actions::apply;
|
||||
// allow empty_subject to exists
|
||||
template <typename Action, auto V> constexpr static auto apply(Action, term<V>, empty_subject) -> empty_subject { return {}; }
|
||||
template <typename Action> constexpr static auto apply(Action, epsilon, empty_subject) -> empty_subject { return {}; }
|
||||
};
|
||||
|
||||
template <typename Actions> struct ignore_unknown: public Actions {
|
||||
using Actions::apply;
|
||||
// allow flow thru unknown actions
|
||||
template <typename Action, auto V, typename Subject> constexpr static auto apply(Action, term<V>, Subject) -> Subject { return {}; }
|
||||
template <typename Action, typename Subject> constexpr static auto apply(Action, epsilon, Subject) -> Subject { return {}; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,223 @@
|
|||
#ifndef CTLL__FIXED_STRING__GPP
|
||||
#define CTLL__FIXED_STRING__GPP
|
||||
|
||||
#ifndef CTLL_IN_A_MODULE
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#include "utilities.hpp"
|
||||
|
||||
namespace ctll {
|
||||
|
||||
struct length_value_t {
|
||||
uint32_t value;
|
||||
uint8_t length;
|
||||
};
|
||||
|
||||
constexpr length_value_t length_and_value_of_utf8_code_point(uint8_t first_unit) noexcept {
|
||||
if ((first_unit & 0b1000'0000) == 0b0000'0000) return {static_cast<uint32_t>(first_unit), 1};
|
||||
else if ((first_unit & 0b1110'0000) == 0b1100'0000) return {static_cast<uint32_t>(first_unit & 0b0001'1111), 2};
|
||||
else if ((first_unit & 0b1111'0000) == 0b1110'0000) return {static_cast<uint32_t>(first_unit & 0b0000'1111), 3};
|
||||
else if ((first_unit & 0b1111'1000) == 0b1111'0000) return {static_cast<uint32_t>(first_unit & 0b0000'0111), 4};
|
||||
else if ((first_unit & 0b1111'1100) == 0b1111'1000) return {static_cast<uint32_t>(first_unit & 0b0000'0011), 5};
|
||||
else if ((first_unit & 0b1111'1100) == 0b1111'1100) return {static_cast<uint32_t>(first_unit & 0b0000'0001), 6};
|
||||
else return {0, 0};
|
||||
}
|
||||
|
||||
constexpr char32_t value_of_trailing_utf8_code_point(uint8_t unit, bool & correct) noexcept {
|
||||
if ((unit & 0b1100'0000) == 0b1000'0000) return unit & 0b0011'1111;
|
||||
else {
|
||||
correct = false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr length_value_t length_and_value_of_utf16_code_point(uint16_t first_unit) noexcept {
|
||||
if ((first_unit & 0b1111110000000000) == 0b1101'1000'0000'0000) return {static_cast<uint32_t>(first_unit & 0b0000001111111111), 2};
|
||||
else return {first_unit, 1};
|
||||
}
|
||||
|
||||
struct construct_from_pointer_t { };
|
||||
|
||||
constexpr auto construct_from_pointer = construct_from_pointer_t{};
|
||||
|
||||
CTLL_EXPORT template <size_t N> struct fixed_string {
|
||||
char32_t content[N] = {};
|
||||
size_t real_size{0};
|
||||
bool correct_flag{true};
|
||||
|
||||
template <typename T> constexpr fixed_string(construct_from_pointer_t, const T * input) noexcept {
|
||||
if constexpr (std::is_same_v<T, char>) {
|
||||
#ifdef CTRE_STRING_IS_UTF8
|
||||
size_t out{0};
|
||||
for (size_t i{0}; i < N; ++i) {
|
||||
length_value_t info = length_and_value_of_utf8_code_point(input[i]);
|
||||
switch (info.length) {
|
||||
case 6:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 5:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 4:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 3:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 2:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 1:
|
||||
content[out++] = static_cast<char32_t>(info.value);
|
||||
real_size++;
|
||||
break;
|
||||
default:
|
||||
correct_flag = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (size_t i{0}; i < N; ++i) {
|
||||
content[i] = static_cast<uint8_t>(input[i]);
|
||||
real_size++;
|
||||
}
|
||||
#endif
|
||||
#if __cpp_char8_t
|
||||
} else if constexpr (std::is_same_v<T, char8_t>) {
|
||||
size_t out{0};
|
||||
for (size_t i{0}; i < N; ++i) {
|
||||
length_value_t info = length_and_value_of_utf8_code_point(input[i]);
|
||||
switch (info.length) {
|
||||
case 6:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 5:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 4:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 3:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 2:
|
||||
if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag);
|
||||
[[fallthrough]];
|
||||
case 1:
|
||||
content[out++] = static_cast<char32_t>(info.value);
|
||||
real_size++;
|
||||
break;
|
||||
default:
|
||||
correct_flag = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if constexpr (std::is_same_v<T, char16_t>) {
|
||||
size_t out{0};
|
||||
for (size_t i{0}; i < N; ++i) {
|
||||
length_value_t info = length_and_value_of_utf16_code_point(input[i]);
|
||||
if (info.length == 2) {
|
||||
if (++i < N) {
|
||||
if ((input[i] & 0b1111'1100'0000'0000) == 0b1101'1100'0000'0000) {
|
||||
content[out++] = ((info.value << 10) | (input[i] & 0b0000'0011'1111'1111)) + 0x10000;
|
||||
} else {
|
||||
correct_flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
content[out++] = info.value;
|
||||
}
|
||||
}
|
||||
real_size = out;
|
||||
} else if constexpr (std::is_same_v<T, wchar_t> || std::is_same_v<T, char32_t>) {
|
||||
for (size_t i{0}; i < N; ++i) {
|
||||
content[i] = static_cast<char32_t>(input[i]);
|
||||
real_size++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> constexpr fixed_string(const std::array<T, N> & in) noexcept: fixed_string{construct_from_pointer, in.data()} { }
|
||||
template <typename T> constexpr fixed_string(const T (&input)[N+1]) noexcept: fixed_string{construct_from_pointer, input} { }
|
||||
|
||||
constexpr fixed_string(const fixed_string & other) noexcept {
|
||||
for (size_t i{0}; i < N; ++i) {
|
||||
content[i] = other.content[i];
|
||||
}
|
||||
real_size = other.real_size;
|
||||
correct_flag = other.correct_flag;
|
||||
}
|
||||
constexpr bool correct() const noexcept {
|
||||
return correct_flag;
|
||||
}
|
||||
constexpr size_t size() const noexcept {
|
||||
return real_size;
|
||||
}
|
||||
constexpr const char32_t * begin() const noexcept {
|
||||
return content;
|
||||
}
|
||||
constexpr const char32_t * end() const noexcept {
|
||||
return content + size();
|
||||
}
|
||||
constexpr char32_t operator[](size_t i) const noexcept {
|
||||
return content[i];
|
||||
}
|
||||
template <size_t M> constexpr bool is_same_as(const fixed_string<M> & rhs) const noexcept {
|
||||
if (real_size != rhs.size()) return false;
|
||||
for (size_t i{0}; i != real_size; ++i) {
|
||||
if (content[i] != rhs[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
constexpr operator std::basic_string_view<char32_t>() const noexcept {
|
||||
return std::basic_string_view<char32_t>{content, size()};
|
||||
}
|
||||
};
|
||||
|
||||
template <> class fixed_string<0> {
|
||||
static constexpr char32_t empty[1] = {0};
|
||||
public:
|
||||
template <typename T> constexpr fixed_string(const T *) noexcept {
|
||||
|
||||
}
|
||||
constexpr fixed_string(std::initializer_list<char32_t>) noexcept {
|
||||
|
||||
}
|
||||
constexpr fixed_string(const fixed_string &) noexcept {
|
||||
|
||||
}
|
||||
constexpr bool correct() const noexcept {
|
||||
return true;
|
||||
}
|
||||
constexpr size_t size() const noexcept {
|
||||
return 0;
|
||||
}
|
||||
constexpr const char32_t * begin() const noexcept {
|
||||
return empty;
|
||||
}
|
||||
constexpr const char32_t * end() const noexcept {
|
||||
return empty + size();
|
||||
}
|
||||
constexpr char32_t operator[](size_t) const noexcept {
|
||||
return 0;
|
||||
}
|
||||
constexpr operator std::basic_string_view<char32_t>() const noexcept {
|
||||
return std::basic_string_view<char32_t>{empty, 0};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CharT, size_t N> fixed_string(const CharT (&)[N]) -> fixed_string<N-1>;
|
||||
template <typename CharT, size_t N> fixed_string(const std::array<CharT,N> &) -> fixed_string<N>;
|
||||
|
||||
template <size_t N> fixed_string(fixed_string<N>) -> fixed_string<N>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,123 @@
|
|||
#ifndef CTLL__GRAMMARS__HPP
|
||||
#define CTLL__GRAMMARS__HPP
|
||||
|
||||
namespace ctll {
|
||||
|
||||
// terminal type representing symbol / character of any type
|
||||
template <auto v> struct term {
|
||||
static constexpr auto value = v;
|
||||
};
|
||||
|
||||
// epsilon = nothing on input tape
|
||||
// also used as an command for parsing means "do nothing"
|
||||
struct epsilon {
|
||||
static constexpr auto value = '-';
|
||||
};
|
||||
|
||||
// empty_stack_symbol = nothing on stack
|
||||
struct empty_stack_symbol {};
|
||||
|
||||
// push<T...> is alias to list<T...>
|
||||
template <typename... Ts> using push = list<Ts...>;
|
||||
|
||||
// accept/reject type for controlling output of LL1 machine
|
||||
struct accept { constexpr explicit operator bool() noexcept { return true; } };
|
||||
struct reject { constexpr explicit operator bool() noexcept { return false; } };
|
||||
|
||||
// action type, every action item in grammar must inherit from
|
||||
struct action {
|
||||
struct action_tag { };
|
||||
};
|
||||
|
||||
// move one character forward and pop it from stack command
|
||||
struct pop_input {
|
||||
struct pop_input_tag { };
|
||||
};
|
||||
|
||||
// additional overloads for type list
|
||||
template <typename... Ts> constexpr auto push_front(pop_input, list<Ts...>) -> list<Ts...> { return {}; }
|
||||
|
||||
template <typename... Ts> constexpr auto push_front(epsilon, list<Ts...>) -> list<Ts...> { return {}; }
|
||||
|
||||
template <typename... As, typename... Bs> constexpr auto push_front(list<As...>, list<Bs...>) -> list<As..., Bs...> { return {}; }
|
||||
|
||||
template <typename T, typename... As> constexpr auto pop_front_and_push_front(T item, list<As...> l) {
|
||||
return push_front(item, pop_front(l));
|
||||
}
|
||||
|
||||
// SPECIAL matching types for nicer grammars
|
||||
|
||||
// match any term
|
||||
struct anything {
|
||||
constexpr inline anything() noexcept { }
|
||||
template <auto V> constexpr anything(term<V>) noexcept;
|
||||
};
|
||||
|
||||
// match range of term A-B
|
||||
template <auto A, decltype(A) B> struct range {
|
||||
constexpr inline range() noexcept { }
|
||||
//template <auto V> constexpr range(term<V>) noexcept requires (A <= V) && (V <= B);
|
||||
template <auto V, typename = std::enable_if_t<(A <= V) && (V <= B)>> constexpr range(term<V>) noexcept;
|
||||
};
|
||||
|
||||
#ifdef __EDG__
|
||||
template <auto V, auto... Set> struct contains {
|
||||
static constexpr bool value = ((Set == V) || ... || false);
|
||||
};
|
||||
#endif
|
||||
|
||||
// match terms defined in set
|
||||
template <auto... Def> struct set {
|
||||
constexpr inline set() noexcept { }
|
||||
#ifdef __EDG__
|
||||
template <auto V, typename = std::enable_if_t<contains<V, Def...>::value>> constexpr set(term<V>) noexcept;
|
||||
#else
|
||||
template <auto V, typename = std::enable_if_t<((Def == V) || ... || false)>> constexpr set(term<V>) noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
// match terms not defined in set
|
||||
template <auto... Def> struct neg_set {
|
||||
constexpr inline neg_set() noexcept { }
|
||||
|
||||
#ifdef __EDG__
|
||||
template <auto V, typename = std::enable_if_t<!contains<V, Def...>::value>> constexpr neg_set(term<V>) noexcept;
|
||||
#else
|
||||
template <auto V, typename = std::enable_if_t<!((Def == V) || ... || false)>> constexpr neg_set(term<V>) noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
// AUGMENTED grammar which completes user-defined grammar for all other cases
|
||||
template <typename Grammar> struct augment_grammar: public Grammar {
|
||||
// start nonterminal is defined in parent type
|
||||
using typename Grammar::_start;
|
||||
|
||||
// grammar rules are inherited from Grammar parent type
|
||||
using Grammar::rule;
|
||||
|
||||
// term on stack and on input means pop_input;
|
||||
template <auto A> static constexpr auto rule(term<A>, term<A>) -> ctll::pop_input;
|
||||
|
||||
// if the type on stack (range, set, neg_set, anything) is constructible from the terminal => pop_input
|
||||
template <typename Expected, auto V> static constexpr auto rule(Expected, term<V>) -> std::enable_if_t<std::is_constructible_v<Expected, term<V>>, ctll::pop_input>;
|
||||
|
||||
// empty stack and empty input means we are accepting
|
||||
static constexpr auto rule(empty_stack_symbol, epsilon) -> ctll::accept;
|
||||
|
||||
// not matching anything else => reject
|
||||
static constexpr auto rule(...) -> ctll::reject;
|
||||
|
||||
// start stack is just a list<Grammar::_start>;
|
||||
using start_stack = list<typename Grammar::_start>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
#ifndef CTLL__TYPE_STACK__HPP
|
||||
#define CTLL__TYPE_STACK__HPP
|
||||
|
||||
#include "utilities.hpp"
|
||||
|
||||
namespace ctll {
|
||||
|
||||
template <typename... Ts> struct list { };
|
||||
|
||||
struct _nothing { };
|
||||
|
||||
using empty_list = list<>;
|
||||
|
||||
// calculate size of list content
|
||||
template <typename... Ts> constexpr auto size(list<Ts...>) noexcept { return sizeof...(Ts); }
|
||||
|
||||
|
||||
// check if the list is empty
|
||||
template <typename... Ts> constexpr bool empty(list<Ts...>) noexcept { return false; }
|
||||
constexpr bool empty(empty_list) { return true; }
|
||||
|
||||
|
||||
// concat two lists together left to right
|
||||
template <typename... As, typename... Bs> constexpr auto concat(list<As...>, list<Bs...>) noexcept -> list<As..., Bs...> { return {}; }
|
||||
|
||||
|
||||
// push something to the front of a list
|
||||
template <typename T, typename... As> constexpr auto push_front(T, list<As...>) noexcept -> list<T, As...> { return {}; }
|
||||
|
||||
|
||||
// pop element from the front of a list
|
||||
template <typename T, typename... As> constexpr auto pop_front(list<T, As...>) noexcept -> list<As...> { return {}; }
|
||||
constexpr auto pop_front(empty_list) -> empty_list;
|
||||
|
||||
// pop element from the front of a list and return new typelist too
|
||||
template <typename Front, typename List> struct list_pop_pair {
|
||||
Front front{};
|
||||
List list{};
|
||||
constexpr list_pop_pair() = default;
|
||||
};
|
||||
|
||||
template <typename Head, typename... As, typename T = _nothing> constexpr auto pop_and_get_front(list<Head, As...>, T = T()) noexcept -> list_pop_pair<Head, list<As...>> { return {}; }
|
||||
template <typename T = _nothing> constexpr auto pop_and_get_front(empty_list, T = T()) noexcept -> list_pop_pair<T, empty_list> { return {}; }
|
||||
|
||||
|
||||
// return front of the list
|
||||
template <typename Head, typename... As, typename T = _nothing> constexpr auto front(list<Head, As...>, T = T()) noexcept -> Head { return {}; }
|
||||
template <typename T = _nothing> constexpr auto front(empty_list, T = T()) noexcept -> T { return {}; }
|
||||
|
||||
// rotate list
|
||||
template <typename T> struct rotate_item {
|
||||
template <typename... Ts> friend constexpr auto operator+(list<Ts...>, rotate_item<T>) noexcept -> list<T, Ts...> { return {}; }
|
||||
};
|
||||
|
||||
template <typename... Ts> constexpr auto rotate(list<Ts...>) -> decltype((list<>{} + ... + rotate_item<Ts>{})) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// set operations
|
||||
template <typename T> struct item_matcher {
|
||||
struct not_selected {
|
||||
template <typename... Ts> friend constexpr auto operator+(list<Ts...>, not_selected) -> list<Ts...>;
|
||||
};
|
||||
template <typename Y> struct wrapper {
|
||||
template <typename... Ts> friend constexpr auto operator+(list<Ts...>, wrapper<Y>) -> list<Ts...,Y>;
|
||||
};
|
||||
|
||||
static constexpr auto check(T) { return std::true_type{}; }
|
||||
static constexpr auto check(...) { return std::false_type{}; }
|
||||
static constexpr auto select(T) { return not_selected{}; }
|
||||
template <typename Y> static constexpr auto select(Y) { return wrapper<Y>{}; }
|
||||
};
|
||||
|
||||
template <typename T, typename... Ts> constexpr bool exists_in(T, list<Ts...>) noexcept {
|
||||
return (item_matcher<T>::check(Ts{}) || ... || false);
|
||||
}
|
||||
|
||||
template <typename T, typename... Ts> constexpr auto add_item(T item, list<Ts...> l) noexcept {
|
||||
if constexpr (exists_in(item, l)) {
|
||||
return l;
|
||||
} else {
|
||||
return list<Ts..., T>{};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... Ts> constexpr auto remove_item(T, list<Ts...>) noexcept {
|
||||
item_matcher<T> matcher;
|
||||
return decltype((list<>{} + ... + matcher.select(Ts{}))){};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,192 @@
|
|||
#ifndef CTLL__PARSER__HPP
|
||||
#define CTLL__PARSER__HPP
|
||||
|
||||
#include "fixed_string.hpp"
|
||||
#include "list.hpp"
|
||||
#include "grammars.hpp"
|
||||
#include "actions.hpp"
|
||||
|
||||
#ifndef CTLL_IN_A_MODULE
|
||||
#include <limits>
|
||||
#endif
|
||||
|
||||
namespace ctll {
|
||||
|
||||
|
||||
enum class decision {
|
||||
reject,
|
||||
accept,
|
||||
undecided
|
||||
};
|
||||
|
||||
struct placeholder { };
|
||||
|
||||
template <size_t> using index_placeholder = placeholder;
|
||||
|
||||
#if CTLL_CNTTP_COMPILER_CHECK
|
||||
template <typename Grammar, ctll::fixed_string input, typename ActionSelector = empty_actions, bool IgnoreUnknownActions = false> struct parser { // in c++20
|
||||
#else
|
||||
template <typename Grammar, const auto & input, typename ActionSelector = empty_actions, bool IgnoreUnknownActions = false> struct parser {
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__ // workaround to GCC bug
|
||||
#if CTLL_CNTTP_COMPILER_CHECK
|
||||
static constexpr auto _input = input; // c++20 mode
|
||||
#else
|
||||
static constexpr auto & _input = input; // c++17 mode
|
||||
#endif
|
||||
#else
|
||||
static constexpr auto _input = input; // everyone else
|
||||
#endif
|
||||
|
||||
using Actions = ctll::conditional<IgnoreUnknownActions, ignore_unknown<ActionSelector>, identity<ActionSelector>>;
|
||||
using grammar = augment_grammar<Grammar>;
|
||||
|
||||
template <size_t Pos, typename Stack, typename Subject, decision Decision> struct results {
|
||||
|
||||
static constexpr bool is_correct = Decision == decision::accept;
|
||||
|
||||
constexpr inline CTLL_FORCE_INLINE operator bool() const noexcept {
|
||||
return is_correct;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__ // workaround to GCC bug
|
||||
#if CTLL_CNTTP_COMPILER_CHECK
|
||||
static constexpr auto _input = input; // c++20 mode
|
||||
#else
|
||||
static constexpr auto & _input = input; // c++17 mode
|
||||
#endif
|
||||
#else
|
||||
static constexpr auto _input = input; // everyone else
|
||||
#endif
|
||||
|
||||
using output_type = Subject;
|
||||
static constexpr size_t position = Pos;
|
||||
|
||||
constexpr auto operator+(placeholder) const noexcept {
|
||||
if constexpr (Decision == decision::undecided) {
|
||||
// parse for current char (RPos) with previous stack and subject :)
|
||||
return parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template decide<Pos, Stack, Subject>({}, {});
|
||||
} else {
|
||||
// if there is decision already => just push it to the end of fold expression
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t Pos> static constexpr auto get_current_term() noexcept {
|
||||
if constexpr (Pos < input.size()) {
|
||||
constexpr auto value = input[Pos];
|
||||
if constexpr (value <= static_cast<decltype(value)>((std::numeric_limits<char>::max)())) {
|
||||
return term<static_cast<char>(value)>{};
|
||||
} else {
|
||||
return term<value>{};
|
||||
}
|
||||
|
||||
} else {
|
||||
// return epsilon if we are past the input
|
||||
return epsilon{};
|
||||
}
|
||||
}
|
||||
template <size_t Pos> static constexpr auto get_previous_term() noexcept {
|
||||
if constexpr (Pos == 0) {
|
||||
// there is no previous character on input if we are on start
|
||||
return epsilon{};
|
||||
} else if constexpr ((Pos-1) < input.size()) {
|
||||
constexpr auto value = input[Pos-1];
|
||||
if constexpr (value <= static_cast<decltype(value)>((std::numeric_limits<char>::max)())) {
|
||||
return term<static_cast<char>(value)>{};
|
||||
} else {
|
||||
return term<value>{};
|
||||
}
|
||||
} else {
|
||||
return epsilon{};
|
||||
}
|
||||
}
|
||||
// if rule is accept => return true and subject
|
||||
template <size_t Pos, typename Terminal, typename Stack, typename Subject>
|
||||
static constexpr auto move(ctll::accept, Terminal, Stack, Subject) noexcept {
|
||||
return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos, Stack, Subject, decision::accept>();
|
||||
}
|
||||
// if rule is reject => return false and subject
|
||||
template <size_t Pos, typename Terminal, typename Stack, typename Subject>
|
||||
static constexpr auto move(ctll::reject, Terminal, Stack, Subject) noexcept {
|
||||
return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos, Stack, Subject, decision::reject>();
|
||||
}
|
||||
// if rule is pop_input => move to next character
|
||||
template <size_t Pos, typename Terminal, typename Stack, typename Subject>
|
||||
static constexpr auto move(ctll::pop_input, Terminal, Stack, Subject) noexcept {
|
||||
return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos+1, Stack, Subject, decision::undecided>();
|
||||
}
|
||||
// if rule is string => push it to the front of stack
|
||||
template <size_t Pos, typename... Content, typename Terminal, typename Stack, typename Subject>
|
||||
static constexpr auto move(push<Content...> string, Terminal, Stack stack, Subject subject) noexcept {
|
||||
return decide<Pos>(push_front(string, stack), subject);
|
||||
}
|
||||
// if rule is epsilon (empty string) => continue
|
||||
template <size_t Pos, typename Terminal, typename Stack, typename Subject>
|
||||
static constexpr auto move(epsilon, Terminal, Stack stack, Subject subject) noexcept {
|
||||
return decide<Pos>(stack, subject);
|
||||
}
|
||||
// if rule is string with current character at the beginning (term<V>) => move to next character
|
||||
// and push string without the character (quick LL(1))
|
||||
template <size_t Pos, auto V, typename... Content, typename Stack, typename Subject>
|
||||
static constexpr auto move(push<term<V>, Content...>, term<V>, Stack stack, Subject) noexcept {
|
||||
constexpr auto local_input = input;
|
||||
return typename parser<Grammar, local_input, ActionSelector, IgnoreUnknownActions>::template results<Pos+1, decltype(push_front(list<Content...>(), stack)), Subject, decision::undecided>();
|
||||
}
|
||||
// if rule is string with any character at the beginning (compatible with current term<T>) => move to next character
|
||||
// and push string without the character (quick LL(1))
|
||||
template <size_t Pos, auto V, typename... Content, auto T, typename Stack, typename Subject>
|
||||
static constexpr auto move(push<anything, Content...>, term<T>, Stack stack, Subject) noexcept {
|
||||
constexpr auto local_input = input;
|
||||
return typename parser<Grammar, local_input, ActionSelector, IgnoreUnknownActions>::template results<Pos+1, decltype(push_front(list<Content...>(), stack)), Subject, decision::undecided>();
|
||||
}
|
||||
// decide if we need to take action or move
|
||||
template <size_t Pos, typename Stack, typename Subject> static constexpr auto decide(Stack previous_stack, Subject previous_subject) noexcept {
|
||||
// each call means we pop something from stack
|
||||
auto top_symbol = decltype(ctll::front(previous_stack, empty_stack_symbol()))();
|
||||
// gcc pedantic warning
|
||||
[[maybe_unused]] auto stack = decltype(ctll::pop_front(previous_stack))();
|
||||
|
||||
// in case top_symbol is action type (apply it on previous subject and get new one)
|
||||
if constexpr (std::is_base_of_v<ctll::action, decltype(top_symbol)>) {
|
||||
auto subject = Actions::apply(top_symbol, get_previous_term<Pos>(), previous_subject);
|
||||
|
||||
// in case that semantic action is error => reject input
|
||||
if constexpr (std::is_same_v<ctll::reject, decltype(subject)>) {
|
||||
return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos, Stack, Subject, decision::reject>();
|
||||
} else {
|
||||
return decide<Pos>(stack, subject);
|
||||
}
|
||||
} else {
|
||||
// all other cases are ordinary for LL(1) parser
|
||||
auto current_term = get_current_term<Pos>();
|
||||
auto rule = decltype(grammar::rule(top_symbol,current_term))();
|
||||
return move<Pos>(rule, current_term, stack, previous_subject);
|
||||
}
|
||||
}
|
||||
|
||||
// trampolines with folded expression
|
||||
template <typename Subject, size_t... Pos> static constexpr auto trampoline_decide(Subject, std::index_sequence<Pos...>) noexcept {
|
||||
// parse everything for first char and than for next and next ...
|
||||
// Pos+1 is needed as we want to finish calculation with epsilons on stack
|
||||
auto v = (decide<0, typename grammar::start_stack, Subject>({}, {}) + ... + index_placeholder<Pos+1>());
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename Subject = empty_subject> static constexpr auto trampoline_decide(Subject subject = {}) noexcept {
|
||||
// there will be no recursion, just sequence long as the input
|
||||
return trampoline_decide(subject, std::make_index_sequence<input.size()>());
|
||||
}
|
||||
|
||||
template <typename Subject = empty_subject> using output = decltype(trampoline_decide<Subject>());
|
||||
template <typename Subject = empty_subject> static inline constexpr bool correct_with = trampoline_decide<Subject>();
|
||||
|
||||
};
|
||||
|
||||
} // end of ctll namespace
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef CTLL__UTILITIES__HPP
|
||||
#define CTLL__UTILITIES__HPP
|
||||
|
||||
#ifndef CTLL_IN_A_MODULE
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
#ifdef CTLL_IN_A_MODULE
|
||||
#define CTLL_EXPORT export
|
||||
#else
|
||||
#define CTLL_EXPORT
|
||||
#endif
|
||||
|
||||
#if defined __cpp_nontype_template_parameter_class
|
||||
#define CTLL_CNTTP_COMPILER_CHECK 1
|
||||
#elif defined __cpp_nontype_template_args
|
||||
// compiler which defines correctly feature test macro (not you clang)
|
||||
#if __cpp_nontype_template_args >= 201911L
|
||||
#define CTLL_CNTTP_COMPILER_CHECK 1
|
||||
#elif __cpp_nontype_template_args >= 201411L
|
||||
// appleclang 13+
|
||||
#if defined __apple_build_version__
|
||||
#if defined __clang_major__ && __clang_major__ >= 13
|
||||
// but only in c++20 and more
|
||||
#if __cplusplus > 201703L
|
||||
#define CTLL_CNTTP_COMPILER_CHECK 1
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
// clang 12+
|
||||
#if defined __clang_major__ && __clang_major__ >= 12
|
||||
// but only in c++20 and more
|
||||
#if __cplusplus > 201703L
|
||||
#define CTLL_CNTTP_COMPILER_CHECK 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CTLL_CNTTP_COMPILER_CHECK
|
||||
#define CTLL_CNTTP_COMPILER_CHECK 0
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define CTLL_FORCE_INLINE __forceinline
|
||||
#else
|
||||
#define CTLL_FORCE_INLINE __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
namespace ctll {
|
||||
|
||||
template <bool> struct conditional_helper;
|
||||
|
||||
template <> struct conditional_helper<true> {
|
||||
template <typename A, typename> using type = A;
|
||||
};
|
||||
|
||||
template <> struct conditional_helper<false> {
|
||||
template <typename, typename B> using type = B;
|
||||
};
|
||||
|
||||
template <bool V, typename A, typename B> using conditional = typename conditional_helper<V>::template type<A,B>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef CTRE_V2__CTRE_UNICODE__HPP
|
||||
#define CTRE_V2__CTRE_UNICODE__HPP
|
||||
|
||||
#include "ctre.hpp"
|
||||
#include "unicode-db.hpp"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef CTRE_V2__CTRE__HPP
|
||||
#define CTRE_V2__CTRE__HPP
|
||||
|
||||
#include "ctre/literals.hpp"
|
||||
#include "ctre/functions.hpp"
|
||||
#include "ctre/iterators.hpp"
|
||||
#include "ctre/range.hpp"
|
||||
#include "ctre/operators.hpp"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef CTRE__ACTIONS__ASSERTS__HPP
|
||||
#define CTRE__ACTIONS__ASSERTS__HPP
|
||||
|
||||
// push_assert_begin
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_begin, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(assert_line_begin(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// push_assert_end
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_end, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(assert_line_end(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// push_assert_begin
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_subject_begin, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(assert_subject_begin(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// push_assert_subject_end
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_subject_end, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(assert_subject_end(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// push_assert_subject_end_with_lineend
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_subject_end_with_lineend, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(assert_subject_end_line(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef CTRE__ACTIONS__ATOMIC_GROUP__HPP
|
||||
#define CTRE__ACTIONS__ATOMIC_GROUP__HPP
|
||||
|
||||
// atomic start
|
||||
template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_atomic, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<atomic_start, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// atomic
|
||||
template <auto V, typename Atomic, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_atomic, ctll::term<V>, pcre_context<ctll::list<Atomic, atomic_start, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<atomic_group<Atomic>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// atomic sequence
|
||||
template <auto V, typename... Atomic, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_atomic, ctll::term<V>, pcre_context<ctll::list<sequence<Atomic...>, atomic_start, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<atomic_group<Atomic...>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef CTRE__ACTIONS__BACKREFERENCE__HPP
|
||||
#define CTRE__ACTIONS__BACKREFERENCE__HPP
|
||||
|
||||
// backreference with name
|
||||
template <auto... Str, auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_back_reference, ctll::term<V>, pcre_context<ctll::list<id<Str...>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::push_front(back_reference_with_name<id<Str...>>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// with just a number
|
||||
template <auto V, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_back_reference, ctll::term<V>, pcre_context<ctll::list<number<Id>, Ts...>, pcre_parameters<Counter>>) {
|
||||
// if we are looking outside of existing list of Ids ... reject input during parsing
|
||||
if constexpr (Counter < Id) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return pcre_context{ctll::push_front(back_reference<Id>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
|
||||
}
|
||||
}
|
||||
|
||||
// relative backreference
|
||||
template <auto V, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_relative_back_reference, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<number<Id>, Ts...>, pcre_parameters<Counter>>) {
|
||||
// if we are looking outside of existing list of Ids ... reject input during parsing
|
||||
if constexpr (Counter < Id) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
constexpr size_t absolute_id = (Counter + 1) - Id;
|
||||
return pcre_context{ctll::push_front(back_reference<absolute_id>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef CTRE__ACTIONS__BOUNDARIES__HPP
|
||||
#define CTRE__ACTIONS__BOUNDARIES__HPP
|
||||
|
||||
// push_word_boundary
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_word_boundary, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(boundary<word_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// push_not_word_boundary
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_not_word_boundary, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(boundary<negative_set<word_chars>>(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef CTRE__ACTIONS__CAPTURE__HPP
|
||||
#define CTRE__ACTIONS__CAPTURE__HPP
|
||||
|
||||
// prepare_capture
|
||||
template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::prepare_capture, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::push_front(capture_id<Counter+1>(), ctll::list<Ts...>()), pcre_parameters<Counter+1>()};
|
||||
}
|
||||
|
||||
// reset_capture
|
||||
template <auto V, typename... Ts, size_t Id, size_t Counter> static constexpr auto apply(pcre::reset_capture, ctll::term<V>, pcre_context<ctll::list<capture_id<Id>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<Ts...>(), pcre_parameters<Counter-1>()};
|
||||
}
|
||||
|
||||
// capture
|
||||
template <auto V, typename A, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_capture, ctll::term<V>, pcre_context<ctll::list<A, capture_id<Id>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::push_front(capture<Id, A>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
|
||||
}
|
||||
// capture (sequence)
|
||||
template <auto V, typename... Content, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_capture, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, capture_id<Id>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::push_front(capture<Id, Content...>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
|
||||
}
|
||||
// push_name
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_name, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(id<V>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_name (concat)
|
||||
template <auto... Str, auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_name, ctll::term<V>, pcre_context<ctll::list<id<Str...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(id<Str..., V>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// capture with name
|
||||
template <auto... Str, auto V, typename A, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_capture_with_name, ctll::term<V>, pcre_context<ctll::list<A, id<Str...>, capture_id<Id>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::push_front(capture_with_name<Id, id<Str...>, A>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
|
||||
}
|
||||
// capture with name (sequence)
|
||||
template <auto... Str, auto V, typename... Content, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_capture_with_name, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, id<Str...>, capture_id<Id>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::push_front(capture_with_name<Id, id<Str...>, Content...>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef CTRE__ACTIONS__CHARACTERS__HPP
|
||||
#define CTRE__ACTIONS__CHARACTERS__HPP
|
||||
|
||||
// push character
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(character<V>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_any_character
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_anything, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(any(), subject.stack), subject.parameters};
|
||||
}
|
||||
// character_alarm
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_alarm, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(character<'\x07'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// character_escape
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_escape, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(character<'\x14'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// character_formfeed
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_formfeed, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(character<'\x0C'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_character_newline
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_newline, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(character<'\x0A'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_character_null
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_null, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(character<'\0'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_character_return_carriage
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_return_carriage, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(character<'\x0D'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_character_tab
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_tab, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(character<'\x09'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef CTRE__ACTIONS__CLASS__HPP
|
||||
#define CTRE__ACTIONS__CLASS__HPP
|
||||
|
||||
// class_digit
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_digit, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::set<ctre::digit_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_non_digit
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_nondigit, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::negative_set<ctre::digit_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_space
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::set<ctre::space_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_nonspace
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_nonspace, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::negative_set<ctre::space_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// class_horizontal_space
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_horizontal_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::set<ctre::horizontal_space_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_horizontal_nonspace
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_non_horizontal_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::negative_set<ctre::horizontal_space_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_vertical_space
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_vertical_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::set<ctre::vertical_space_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_vertical_nonspace
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_non_vertical_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::negative_set<ctre::vertical_space_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// class_word
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_word, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::set<ctre::word_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_nonword
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_nonword, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::negative_set<ctre::word_chars>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_nonnewline
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_nonnewline, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::negative_set<character<'\n'>>(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef CTRE__ACTIONS__FUSION__HPP
|
||||
#define CTRE__ACTIONS__FUSION__HPP
|
||||
|
||||
static constexpr size_t combine_max_repeat_length(size_t A, size_t B) {
|
||||
if (A && B) return A+B;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
template <size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content> static constexpr auto combine_repeat(repeat<MinA, MaxA, Content...>, repeat<MinB, MaxB, Content...>) {
|
||||
return repeat<MinA + MinB, combine_max_repeat_length(MaxA, MaxB), Content...>();
|
||||
}
|
||||
|
||||
template <size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content> static constexpr auto combine_repeat(lazy_repeat<MinA, MaxA, Content...>, lazy_repeat<MinB, MaxB, Content...>) {
|
||||
return lazy_repeat<MinA + MinB, combine_max_repeat_length(MaxA, MaxB), Content...>();
|
||||
}
|
||||
|
||||
template <size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content> static constexpr auto combine_repeat(possessive_repeat<MinA, MaxA, Content...>, possessive_repeat<MinB, MaxB, Content...>) {
|
||||
[[maybe_unused]] constexpr bool first_is_unbounded = (MaxA == 0);
|
||||
[[maybe_unused]] constexpr bool second_is_nonempty = (MinB > 0);
|
||||
[[maybe_unused]] constexpr bool second_can_be_empty = (MinB == 0);
|
||||
|
||||
if constexpr (first_is_unbounded && second_is_nonempty) {
|
||||
// will always reject, but I keep the content, so I have some amount of captures
|
||||
return sequence<reject, Content...>();
|
||||
} else if constexpr (first_is_unbounded) {
|
||||
return possessive_repeat<MinA, MaxA, Content...>();
|
||||
} else if constexpr (second_can_be_empty) {
|
||||
return possessive_repeat<MinA, combine_max_repeat_length(MaxA, MaxB), Content...>();
|
||||
} else {
|
||||
return possessive_repeat<MaxA + MinB, combine_max_repeat_length(MaxA, MaxB), Content...>();
|
||||
}
|
||||
}
|
||||
|
||||
// concat repeat sequences
|
||||
template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<repeat<MinB, MaxB, Content...>, repeat<MinA, MaxA, Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(combine_repeat(repeat<MinA, MaxA, Content...>(), repeat<MinB, MaxB, Content...>()), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// concat lazy repeat sequences
|
||||
template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<lazy_repeat<MinB, MaxB, Content...>, lazy_repeat<MinA, MaxA, Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(combine_repeat(lazy_repeat<MinA, MaxA, Content...>(), lazy_repeat<MinB, MaxB, Content...>()), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// concat possessive repeat seqeunces
|
||||
template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<possessive_repeat<MinB, MaxB, Content...>, possessive_repeat<MinA, MaxA, Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(combine_repeat(possessive_repeat<MinA, MaxA, Content...>(), possessive_repeat<MinB, MaxB, Content...>()), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// concat repeat sequences into sequence
|
||||
template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... As, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<repeat<MinB, MaxB, Content...>, As...>,repeat<MinA, MaxA, Content...>,Ts...>, Parameters> subject) {
|
||||
using result = decltype(combine_repeat(repeat<MinB, MaxB, Content...>(), repeat<MinA, MaxA, Content...>()));
|
||||
|
||||
return pcre_context{ctll::push_front(sequence<result,As...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// concat lazy repeat sequences into sequence
|
||||
template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... As, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<lazy_repeat<MinB, MaxB, Content...>, As...>,lazy_repeat<MinA, MaxA, Content...>,Ts...>, Parameters> subject) {
|
||||
using result = decltype(combine_repeat(lazy_repeat<MinB, MaxB, Content...>(), lazy_repeat<MinA, MaxA, Content...>()));
|
||||
|
||||
return pcre_context{ctll::push_front(sequence<result,As...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// concat possessive repeat sequences into sequence
|
||||
template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... As, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<possessive_repeat<MinB, MaxB, Content...>, As...>,possessive_repeat<MinA, MaxA, Content...>,Ts...>, Parameters> subject) {
|
||||
using result = decltype(combine_repeat(possessive_repeat<MinB, MaxB, Content...>(), possessive_repeat<MinA, MaxA, Content...>()));
|
||||
|
||||
return pcre_context{ctll::push_front(sequence<result,As...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef CTRE__ACTIONS__HEXDEC__HPP
|
||||
#define CTRE__ACTIONS__HEXDEC__HPP
|
||||
|
||||
// hexdec character support (seed)
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::create_hexdec, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(number<0ull>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// hexdec character support (push value)
|
||||
template <auto V, size_t N, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_hexdec, ctll::term<V>, pcre_context<ctll::list<number<N>, Ts...>, Parameters> subject) {
|
||||
constexpr auto previous = N << 4ull;
|
||||
if constexpr (V >= 'a' && V <= 'f') {
|
||||
return pcre_context{ctll::push_front(number<(previous + (V - 'a' + 10))>(), ctll::list<Ts...>()), subject.parameters};
|
||||
} else if constexpr (V >= 'A' && V <= 'F') {
|
||||
return pcre_context{ctll::push_front(number<(previous + (V - 'A' + 10))>(), ctll::list<Ts...>()), subject.parameters};
|
||||
} else {
|
||||
return pcre_context{ctll::push_front(number<(previous + (V - '0'))>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
}
|
||||
// hexdec character support (convert to character)
|
||||
template <auto V, size_t N, typename... Ts, typename Parameters> static constexpr auto apply(pcre::finish_hexdec, ctll::term<V>, pcre_context<ctll::list<number<N>, Ts...>, Parameters> subject) {
|
||||
constexpr size_t max_char = (std::numeric_limits<char>::max)();
|
||||
if constexpr (N <= max_char) {
|
||||
return pcre_context{ctll::push_front(character<char{N}>(), ctll::list<Ts...>()), subject.parameters};
|
||||
} else {
|
||||
return pcre_context{ctll::push_front(character<char32_t{N}>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef CTRE__ACTIONS__LOOKAHEAD__HPP
|
||||
#define CTRE__ACTIONS__LOOKAHEAD__HPP
|
||||
|
||||
// lookahead positive start
|
||||
template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_lookahead_positive, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<look_start<lookahead_positive<>>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookahead positive end
|
||||
template <auto V, typename Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<Look, look_start<lookahead_positive<>>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<lookahead_positive<Look>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookahead positive end (sequence)
|
||||
template <auto V, typename... Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<ctre::sequence<Look...>, look_start<lookahead_positive<>>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<lookahead_positive<Look...>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookahead negative start
|
||||
template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_lookahead_negative, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<look_start<lookahead_negative<>>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookahead negative end
|
||||
template <auto V, typename Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<Look, look_start<lookahead_negative<>>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<lookahead_negative<Look>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookahead negative end (sequence)
|
||||
template <auto V, typename... Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<ctre::sequence<Look...>, look_start<lookahead_negative<>>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<lookahead_negative<Look...>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// LOOKBEHIND
|
||||
|
||||
// lookbehind positive start
|
||||
template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_lookbehind_positive, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<look_start<lookbehind_positive<>>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookbehind positive end
|
||||
template <auto V, typename Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<Look, look_start<lookbehind_positive<>>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<lookbehind_positive<decltype(ctre::rotate_for_lookbehind::rotate(Look{}))>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookbehind positive end (sequence)
|
||||
template <auto V, typename... Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<ctre::sequence<Look...>, look_start<lookbehind_positive<>>, Ts...>, pcre_parameters<Counter>>) {
|
||||
using my_lookbehind = decltype(ctre::convert_to_basic_list<lookbehind_positive>(ctll::rotate(ctll::list<decltype(ctre::rotate_for_lookbehind::rotate(Look{}))...>{})));
|
||||
return pcre_context{ctll::list<my_lookbehind, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookbehind negative start
|
||||
template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_lookbehind_negative, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<look_start<lookbehind_negative<>>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookbehind negative end
|
||||
template <auto V, typename Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<Look, look_start<lookbehind_negative<>>, Ts...>, pcre_parameters<Counter>>) {
|
||||
return pcre_context{ctll::list<lookbehind_negative<decltype(ctre::rotate_for_lookbehind::rotate(Look{}))>, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
// lookbehind negative end (sequence)
|
||||
template <auto V, typename... Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<ctre::sequence<Look...>, look_start<lookbehind_negative<>>, Ts...>, pcre_parameters<Counter>>) {
|
||||
using my_lookbehind = decltype(ctre::convert_to_basic_list<lookbehind_negative>(ctll::rotate(ctll::list<decltype(ctre::rotate_for_lookbehind::rotate(Look{}))...>{})));
|
||||
return pcre_context{ctll::list<my_lookbehind, Ts...>(), pcre_parameters<Counter>()};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef CTRE__ACTIONS__MODE__HPP
|
||||
#define CTRE__ACTIONS__MODE__HPP
|
||||
|
||||
// we need to reset counter and wrap Mode into mode_switch
|
||||
template <typename Mode, typename... Ts, typename Parameters> static constexpr auto apply_mode(Mode, ctll::list<Ts...>, Parameters) {
|
||||
return pcre_context<ctll::list<mode_switch<Mode>, Ts...>, Parameters>{};
|
||||
}
|
||||
|
||||
template <typename Mode, typename... Ts, size_t Id, size_t Counter> static constexpr auto apply_mode(Mode, ctll::list<capture_id<Id>, Ts...>, pcre_parameters<Counter>) {
|
||||
return pcre_context<ctll::list<mode_switch<Mode>, Ts...>, pcre_parameters<Counter-1>>{};
|
||||
}
|
||||
|
||||
// catch a semantic action into mode
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::mode_case_insensitive mode, ctll::term<V>,pcre_context<ctll::list<Ts...>, Parameters>) {
|
||||
return apply_mode(mode, ctll::list<Ts...>{}, Parameters{});
|
||||
}
|
||||
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::mode_case_sensitive mode, ctll::term<V>,pcre_context<ctll::list<Ts...>, Parameters>) {
|
||||
return apply_mode(mode, ctll::list<Ts...>{}, Parameters{});
|
||||
}
|
||||
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::mode_singleline mode, ctll::term<V>,pcre_context<ctll::list<Ts...>, Parameters>) {
|
||||
return apply_mode(mode, ctll::list<Ts...>{}, Parameters{});
|
||||
}
|
||||
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::mode_multiline mode, ctll::term<V>,pcre_context<ctll::list<Ts...>, Parameters>) {
|
||||
return apply_mode(mode, ctll::list<Ts...>{}, Parameters{});
|
||||
}
|
||||
|
||||
// to properly reset capture
|
||||
|
||||
#endif
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef CTRE__ACTIONS__NAMED_CLASS__HPP
|
||||
#define CTRE__ACTIONS__NAMED_CLASS__HPP
|
||||
|
||||
// class_named_alnum
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_alnum, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::alphanum_chars(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_alpha
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_alpha, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::alpha_chars(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_digit
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_digit, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::digit_chars(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_ascii
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_ascii, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::ascii_chars(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_blank
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_blank, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::enumeration<' ','\t'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_cntrl
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_cntrl, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::set<ctre::char_range<'\x00','\x1F'>, ctre::character<'\x7F'>>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_graph
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_graph, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::char_range<'\x21','\x7E'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_lower
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_lower, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::char_range<'a','z'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_upper
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_upper, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::char_range<'A','Z'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_print
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_print, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(ctre::char_range<'\x20','\x7E'>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_space
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(space_chars(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_word
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_word, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(word_chars(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_punct
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_punct, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(punct_chars(), subject.stack), subject.parameters};
|
||||
}
|
||||
// class_named_xdigit
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_xdigit, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(xdigit_chars(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef CTRE__ACTIONS__OPTIONS__HPP
|
||||
#define CTRE__ACTIONS__OPTIONS__HPP
|
||||
|
||||
// empty option for alternate
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_empty, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(empty(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// empty option for empty regex
|
||||
template <typename Parameters> static constexpr auto apply(pcre::push_empty, ctll::epsilon, pcre_context<ctll::list<>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(empty(), subject.stack), subject.parameters};
|
||||
}
|
||||
|
||||
// make_alternate (A|B)
|
||||
template <auto V, typename A, typename B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_alternate, ctll::term<V>, pcre_context<ctll::list<B, A, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(select<A,B>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// make_alternate (As..)|B => (As..|B)
|
||||
template <auto V, typename A, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_alternate, ctll::term<V>, pcre_context<ctll::list<ctre::select<Bs...>, A, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(select<A,Bs...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
|
||||
// make_optional
|
||||
template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(optional<A>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(optional<Content...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// prevent from creating wrapped optionals
|
||||
template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<optional<A>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(optional<A>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// in case inner optional is lazy, result should be lazy too
|
||||
template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<lazy_optional<A>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(lazy_optional<A>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_lazy (optional)
|
||||
template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<optional<Subject...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(lazy_optional<Subject...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// if you already got a lazy optional, make_lazy is no-op
|
||||
template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<lazy_optional<Subject...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(lazy_optional<Subject...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef CTRE__ACTIONS__PROPERTIES__HPP
|
||||
#define CTRE__ACTIONS__PROPERTIES__HPP
|
||||
|
||||
// push_property_name
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_property_name, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(property_name<V>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_property_name (concat)
|
||||
template <auto... Str, auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_property_name, ctll::term<V>, pcre_context<ctll::list<property_name<Str...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(property_name<Str..., V>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// push_property_value
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_property_value, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(property_value<V>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_property_value (concat)
|
||||
template <auto... Str, auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_property_value, ctll::term<V>, pcre_context<ctll::list<property_value<Str...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(property_value<Str..., V>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_property
|
||||
template <auto V, auto... Name, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_property, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<property_name<Name...>, Ts...>, Parameters> subject) {
|
||||
//return ctll::reject{};
|
||||
constexpr char name[sizeof...(Name)]{static_cast<char>(Name)...};
|
||||
constexpr auto p = uni::detail::binary_prop_from_string(get_string_view(name));
|
||||
|
||||
if constexpr (uni::detail::is_unknown(p)) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return pcre_context{ctll::push_front(make_binary_property<p>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
}
|
||||
|
||||
// make_property
|
||||
template <auto V, auto... Value, auto... Name, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_property, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<property_value<Value...>, property_name<Name...>, Ts...>, Parameters> subject) {
|
||||
//return ctll::reject{};
|
||||
constexpr auto prop = property_builder<Name...>::template get<Value...>();
|
||||
|
||||
if constexpr (std::is_same_v<decltype(prop), ctll::reject>) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return pcre_context{ctll::push_front(prop, ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// make_property_negative
|
||||
template <auto V, auto... Name, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_property_negative, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<property_name<Name...>, Ts...>, Parameters> subject) {
|
||||
//return ctll::reject{};
|
||||
constexpr char name[sizeof...(Name)]{static_cast<char>(Name)...};
|
||||
constexpr auto p = uni::detail::binary_prop_from_string(get_string_view(name));
|
||||
|
||||
if constexpr (uni::detail::is_unknown(p)) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return pcre_context{ctll::push_front(negate<make_binary_property<p>>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
}
|
||||
|
||||
// make_property_negative
|
||||
template <auto V, auto... Value, auto... Name, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_property_negative, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<property_value<Value...>, property_name<Name...>, Ts...>, Parameters> subject) {
|
||||
//return ctll::reject{};
|
||||
constexpr auto prop = property_builder<Name...>::template get<Value...>();
|
||||
|
||||
if constexpr (std::is_same_v<decltype(prop), ctll::reject>) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return pcre_context{ctll::push_front(negate<decltype(prop)>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef CTRE__ACTIONS__REPEAT__HPP
|
||||
#define CTRE__ACTIONS__REPEAT__HPP
|
||||
|
||||
// repeat 1..N
|
||||
template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_plus, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(plus<A>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// repeat 1..N (sequence)
|
||||
template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_plus, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(plus<Content...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// repeat 0..N
|
||||
template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_star, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(star<A>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// repeat 0..N (sequence)
|
||||
template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_star, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(star<Content...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// create_number (seed)
|
||||
template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::create_number, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(number<static_cast<size_t>(V - '0')>(), subject.stack), subject.parameters};
|
||||
}
|
||||
// push_number
|
||||
template <auto V, size_t N, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_number, ctll::term<V>, pcre_context<ctll::list<number<N>, Ts...>, Parameters> subject) {
|
||||
constexpr size_t previous = N * 10ull;
|
||||
return pcre_context{ctll::push_front(number<(previous + (V - '0'))>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// repeat A..B
|
||||
template <auto V, typename Subject, size_t A, size_t B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_ab, ctll::term<V>, pcre_context<ctll::list<number<B>, number<A>, Subject, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(repeat<A,B,Subject>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// repeat A..B (sequence)
|
||||
template <auto V, typename... Content, size_t A, size_t B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_ab, ctll::term<V>, pcre_context<ctll::list<number<B>, number<A>, sequence<Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(repeat<A,B,Content...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// repeat_exactly
|
||||
template <auto V, typename Subject, size_t A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_exactly, ctll::term<V>, pcre_context<ctll::list<number<A>, Subject, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(repeat<A,A,Subject>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// repeat_exactly A..B (sequence)
|
||||
template <auto V, typename... Content, size_t A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_exactly, ctll::term<V>, pcre_context<ctll::list<number<A>, sequence<Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(repeat<A,A,Content...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// repeat_at_least (A+)
|
||||
template <auto V, typename Subject, size_t A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_at_least, ctll::term<V>, pcre_context<ctll::list<number<A>, Subject, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(repeat<A,0,Subject>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// repeat_at_least (A+) (sequence)
|
||||
template <auto V, typename... Content, size_t A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_at_least, ctll::term<V>, pcre_context<ctll::list<number<A>, sequence<Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(repeat<A,0,Content...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_lazy (plus)
|
||||
template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<plus<Subject...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(lazy_plus<Subject...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_lazy (star)
|
||||
template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<star<Subject...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(lazy_star<Subject...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_lazy (repeat<A,B>)
|
||||
template <auto V, typename... Subject, size_t A, size_t B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<repeat<A,B,Subject...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(lazy_repeat<A,B,Subject...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_possessive (plus)
|
||||
template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_possessive, ctll::term<V>, pcre_context<ctll::list<plus<Subject...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(possessive_plus<Subject...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_possessive (star)
|
||||
template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_possessive, ctll::term<V>, pcre_context<ctll::list<star<Subject...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(possessive_star<Subject...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_possessive (repeat<A,B>)
|
||||
template <auto V, typename... Subject, size_t A, size_t B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_possessive, ctll::term<V>, pcre_context<ctll::list<repeat<A,B,Subject...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(possessive_repeat<A,B,Subject...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef CTRE__ACTIONS__SEQUENCE__HPP
|
||||
#define CTRE__ACTIONS__SEQUENCE__HPP
|
||||
|
||||
// make_sequence
|
||||
template <auto V, typename A, typename B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<B,A,Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(sequence<A,B>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// make_sequence (concat)
|
||||
template <auto V, typename A, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<Bs...>,A,Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(sequence<A,Bs...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_sequence (make string)
|
||||
template <auto V, auto A, auto B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<character<B>,character<A>,Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(string<A,B>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// make_sequence (concat string)
|
||||
template <auto V, auto A, auto... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<string<Bs...>,character<A>,Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(string<A,Bs...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// make_sequence (make string in front of different items)
|
||||
template <auto V, auto A, auto B, typename... Sq, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<character<B>,Sq...>,character<A>,Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(sequence<string<A,B>,Sq...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// make_sequence (concat string in front of different items)
|
||||
template <auto V, auto A, auto... Bs, typename... Sq, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<string<Bs...>,Sq...>,character<A>,Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(sequence<string<A,Bs...>,Sq...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef CTRE__ACTIONS__SET__HPP
|
||||
#define CTRE__ACTIONS__SET__HPP
|
||||
|
||||
// UTILITY
|
||||
// add into set if not exists
|
||||
template <template <typename...> typename SetType, typename T, typename... As, bool Exists = (std::is_same_v<T, As> || ... || false)> static constexpr auto push_back_into_set(T, SetType<As...>) -> ctll::conditional<Exists, SetType<As...>, SetType<As...,T>> { return {}; }
|
||||
|
||||
//template <template <typename...> typename SetType, typename A, typename BHead, typename... Bs> struct set_merge_helper {
|
||||
// using step = decltype(push_back_into_set<SetType>(BHead(), A()));
|
||||
// using type = ctll::conditional<(sizeof...(Bs) > 0), set_merge_helper<SetType, step, Bs...>, step>;
|
||||
//};
|
||||
//
|
||||
//// add set into set if not exists
|
||||
//template <template <typename...> typename SetType, typename... As, typename... Bs> static constexpr auto push_back_into_set(SetType<As...>, SetType<Bs...>) -> typename set_merge_helper<SetType, SetType<As...>, Bs...>::type { return pcre_context{{};), subject.parameters}}
|
||||
//
|
||||
//template <template <typename...> typename SetType, typename... As> static constexpr auto push_back_into_set(SetType<As...>, SetType<>) -> SetType<As...> { return pcre_context{{};), subject.parameters}}
|
||||
|
||||
|
||||
// END OF UTILITY
|
||||
|
||||
// set_start
|
||||
template <auto V, typename A,typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_start, ctll::term<V>, pcre_context<ctll::list<A,Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(set<A>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// set_make
|
||||
template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_make, ctll::term<V>, pcre_context<ctll::list<set<Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(set<Content...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// set_make_negative
|
||||
template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_make_negative, ctll::term<V>, pcre_context<ctll::list<set<Content...>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(negative_set<Content...>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// set{A...} + B = set{A,B}
|
||||
template <auto V, typename A, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_combine, ctll::term<V>, pcre_context<ctll::list<A,set<Content...>,Ts...>, Parameters> subject) {
|
||||
auto new_set = push_back_into_set<set>(A(), set<Content...>());
|
||||
return pcre_context{ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// TODO checkme
|
||||
//// set{A...} + set{B...} = set{A...,B...}
|
||||
//template <auto V, typename... As, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_combine, ctll::term<V>, pcre_context<ctll::list<set<As...>,set<Bs...>,Ts...>, Parameters> subject) {
|
||||
// auto new_set = push_back_into_set<set>(set<As...>(), set<Bs...>());
|
||||
// return pcre_context{ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters};
|
||||
//}
|
||||
|
||||
// negative_set{A...} + B = negative_set{A,B}
|
||||
template <auto V, typename A, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_combine, ctll::term<V>, pcre_context<ctll::list<A,negative_set<Content...>,Ts...>, Parameters> subject) {
|
||||
auto new_set = push_back_into_set<set>(A(), set<Content...>());
|
||||
return pcre_context{ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
// TODO checkme
|
||||
//// negative_set{A...} + negative_set{B...} = negative_set{A...,B...}
|
||||
//template <auto V, typename... As, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_combine, ctll::term<V>, pcre_context<ctll::list<negative_set<As...>,negative_set<Bs...>,Ts...>, Parameters> subject) {
|
||||
// auto new_set = push_back_into_set<negative_set>(negative_set<As...>(), negative_set<Bs...>());
|
||||
// return pcre_context{ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters};
|
||||
//}
|
||||
// negate_class_named: [[^:digit:]] = [^[:digit:]]
|
||||
template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::negate_class_named, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(negate<A>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
// add range to set
|
||||
template <auto V, auto B, auto A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_range, ctll::term<V>, pcre_context<ctll::list<character<B>,character<A>, Ts...>, Parameters> subject) {
|
||||
return pcre_context{ctll::push_front(char_range<A,B>(), ctll::list<Ts...>()), subject.parameters};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,80 @@
|
|||
#ifndef CTRE__ATOMS__HPP
|
||||
#define CTRE__ATOMS__HPP
|
||||
|
||||
#include "atoms_characters.hpp"
|
||||
#ifndef CTRE_IN_A_MODULE
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
namespace ctre {
|
||||
|
||||
// special helpers for matching
|
||||
struct accept { };
|
||||
struct reject { };
|
||||
struct start_mark { };
|
||||
struct end_mark { };
|
||||
struct end_cycle_mark { };
|
||||
struct end_lookahead_mark { };
|
||||
struct end_lookbehind_mark { };
|
||||
template <size_t Id> struct numeric_mark { };
|
||||
|
||||
struct any { };
|
||||
|
||||
// actual AST of regexp
|
||||
template <auto... Str> struct string { };
|
||||
template <typename... Opts> struct select { };
|
||||
template <typename... Content> struct sequence { };
|
||||
struct empty { };
|
||||
|
||||
template <size_t a, size_t b, typename... Content> struct repeat { };
|
||||
template <typename... Content> using plus = repeat<1,0,Content...>;
|
||||
template <typename... Content> using star = repeat<0,0,Content...>;
|
||||
|
||||
template <size_t a, size_t b, typename... Content> struct lazy_repeat { };
|
||||
template <typename... Content> using lazy_plus = lazy_repeat<1,0,Content...>;
|
||||
template <typename... Content> using lazy_star = lazy_repeat<0,0,Content...>;
|
||||
|
||||
template <size_t a, size_t b, typename... Content> struct possessive_repeat { };
|
||||
template <typename... Content> using possessive_plus = possessive_repeat<1,0,Content...>;
|
||||
template <typename... Content> using possessive_star = possessive_repeat<0,0,Content...>;
|
||||
|
||||
template <typename... Content> using optional = repeat<0,1,Content...>;
|
||||
template <typename... Content> using lazy_optional = lazy_repeat<0,1,Content...>;
|
||||
template <typename... Content> using possessive_optional = possessive_repeat<0,1,Content...>;
|
||||
|
||||
template <size_t Index, typename... Content> struct capture { };
|
||||
|
||||
template <size_t Index, typename Name, typename... Content> struct capture_with_name { };
|
||||
|
||||
template <size_t Index> struct back_reference { };
|
||||
template <typename Name> struct back_reference_with_name { };
|
||||
|
||||
template <typename Type> struct look_start { };
|
||||
|
||||
template <typename... Content> struct lookahead_positive { };
|
||||
template <typename... Content> struct lookahead_negative { };
|
||||
|
||||
template <typename... Content> struct lookbehind_positive { };
|
||||
template <typename... Content> struct lookbehind_negative { };
|
||||
|
||||
struct atomic_start { };
|
||||
|
||||
template <typename... Content> struct atomic_group { };
|
||||
|
||||
template <typename... Content> struct boundary { };
|
||||
template <typename... Content> struct not_boundary { };
|
||||
|
||||
using word_boundary = boundary<word_chars>;
|
||||
using not_word_boundary = not_boundary<word_chars>;
|
||||
|
||||
struct assert_subject_begin { };
|
||||
struct assert_subject_end { };
|
||||
struct assert_subject_end_line{ };
|
||||
struct assert_line_begin { };
|
||||
struct assert_line_end { };
|
||||
|
||||
template <typename> struct mode_switch { };
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,139 @@
|
|||
#ifndef CTRE__ATOMS_CHARACTERS__HPP
|
||||
#define CTRE__ATOMS_CHARACTERS__HPP
|
||||
|
||||
#include "utility.hpp"
|
||||
#include "flags_and_modes.hpp"
|
||||
|
||||
#ifndef CTRE_IN_A_MODULE
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
namespace ctre {
|
||||
|
||||
// sfinae check for types here
|
||||
|
||||
template <typename T> class MatchesCharacter {
|
||||
template <typename Y, typename CharT> static auto test(CharT c) -> decltype(Y::match_char(c, std::declval<const flags &>()), std::true_type());
|
||||
template <typename> static auto test(...) -> std::false_type;
|
||||
public:
|
||||
template <typename CharT> static inline constexpr bool value = decltype(test<T>(std::declval<CharT>()))();
|
||||
};
|
||||
|
||||
template <typename T> constexpr CTRE_FORCE_INLINE bool is_ascii_alpha(T v) {
|
||||
return ((v >= static_cast<T>('a') && v <= static_cast<T>('z')) || (v >= static_cast<T>('A') && v <= static_cast<T>('Z')));
|
||||
}
|
||||
|
||||
template <typename T> constexpr CTRE_FORCE_INLINE bool is_ascii_alpha_lowercase(T v) {
|
||||
return (v >= static_cast<T>('a')) && (v <= static_cast<T>('z'));
|
||||
}
|
||||
|
||||
template <typename T> constexpr CTRE_FORCE_INLINE bool is_ascii_alpha_uppercase(T v) {
|
||||
return (v >= static_cast<T>('A')) && v <= (static_cast<T>('Z'));
|
||||
}
|
||||
|
||||
template <auto V> struct character {
|
||||
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value, const flags & f) noexcept {
|
||||
if constexpr (is_ascii_alpha(V)) {
|
||||
if (is_case_insensitive(f)) {
|
||||
if (value == (V ^ static_cast<decltype(V)>(0x20))) {
|
||||
return true;//
|
||||
}
|
||||
}
|
||||
}
|
||||
return value == V;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Content> struct negative_set {
|
||||
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value, const flags & f) noexcept {
|
||||
return !(Content::match_char(value, f) || ... || false);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Content> struct set {
|
||||
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value, const flags & f) noexcept {
|
||||
return (Content::match_char(value, f) || ... || false);
|
||||
}
|
||||
};
|
||||
|
||||
template <auto... Cs> struct enumeration : set<character<Cs>...> { };
|
||||
|
||||
template <typename... Content> struct negate {
|
||||
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value, const flags & f) noexcept {
|
||||
return !(Content::match_char(value, f) || ... || false);
|
||||
}
|
||||
};
|
||||
|
||||
template <auto A, auto B> struct char_range {
|
||||
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value, const flags & f) noexcept {
|
||||
if constexpr (is_ascii_alpha_lowercase(A) && is_ascii_alpha_lowercase(B)) {
|
||||
if (is_case_insensitive(f)) {
|
||||
if (value >= (A ^ static_cast<decltype(A)>(0x20)) && value <= (B ^ static_cast<decltype(B)>(0x20))) {
|
||||
return true;//
|
||||
}
|
||||
}
|
||||
} else if constexpr (is_ascii_alpha_uppercase(A) && is_ascii_alpha_uppercase(B)) {
|
||||
if (is_case_insensitive(f)) {
|
||||
if (value >= (A ^ static_cast<decltype(A)>(0x20)) && value <= (B ^ static_cast<decltype(B)>(0x20))) {
|
||||
return true;//
|
||||
}
|
||||
}
|
||||
}
|
||||
return (value >= A) && (value <= B);
|
||||
}
|
||||
};
|
||||
using word_chars = set<char_range<'A','Z'>, char_range<'a','z'>, char_range<'0','9'>, character<'_'> >;
|
||||
|
||||
using space_chars = enumeration<' ', '\t', '\n', '\v', '\f', '\r'>;
|
||||
|
||||
using vertical_space_chars = enumeration<
|
||||
char{0x000A}, // Linefeed (LF)
|
||||
char{0x000B}, // Vertical tab (VT)
|
||||
char{0x000C}, // Form feed (FF)
|
||||
char{0x000D}, // Carriage return (CR)
|
||||
char32_t{0x0085}, // Next line (NEL)
|
||||
char32_t{0x2028}, // Line separator
|
||||
char32_t{0x2029} // Paragraph separator
|
||||
>;
|
||||
|
||||
using horizontal_space_chars = enumeration<
|
||||
char{0x0009}, // Horizontal tab (HT)
|
||||
char{0x0020}, // Space
|
||||
char32_t{0x00A0}, // Non-break space
|
||||
char32_t{0x1680}, // Ogham space mark
|
||||
char32_t{0x180E}, // Mongolian vowel separator
|
||||
char32_t{0x2000}, // En quad
|
||||
char32_t{0x2001}, // Em quad
|
||||
char32_t{0x2002}, // En space
|
||||
char32_t{0x2003}, // Em space
|
||||
char32_t{0x2004}, // Three-per-em space
|
||||
char32_t{0x2005}, // Four-per-em space
|
||||
char32_t{0x2006}, // Six-per-em space
|
||||
char32_t{0x2007}, // Figure space
|
||||
char32_t{0x2008}, // Punctuation space
|
||||
char32_t{0x2009}, // Thin space
|
||||
char32_t{0x200A}, // Hair space
|
||||
char32_t{0x202F}, // Narrow no-break space
|
||||
char32_t{0x205F}, // Medium mathematical space
|
||||
char32_t{0x3000} // Ideographic space
|
||||
>;
|
||||
|
||||
using alphanum_chars = set<char_range<'A','Z'>, char_range<'a','z'>, char_range<'0','9'> >;
|
||||
|
||||
using alpha_chars = set<char_range<'A','Z'>, char_range<'a','z'> >;
|
||||
|
||||
using xdigit_chars = set<char_range<'A','F'>, char_range<'a','f'>, char_range<'0','9'> >;
|
||||
|
||||
using punct_chars
|
||||
= enumeration<'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-',
|
||||
'.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']',
|
||||
'^', '_', '`', '{', '|', '}', '~'>;
|
||||
|
||||
using digit_chars = char_range<'0','9'>;
|
||||
|
||||
using ascii_chars = char_range<'\x00','\x7F'>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,157 @@
|
|||
#ifndef CTRE__ATOMS_UNICODE__HPP
|
||||
#define CTRE__ATOMS_UNICODE__HPP
|
||||
|
||||
// master branch is not including unicode db (for now)
|
||||
#include "../unicode-db/unicode_interface.hpp"
|
||||
#include "flags_and_modes.hpp"
|
||||
|
||||
namespace ctre {
|
||||
|
||||
// properties name & value
|
||||
|
||||
template <auto... Str> struct property_name { };
|
||||
template <auto... Str> struct property_value { };
|
||||
|
||||
template <size_t Sz> constexpr std::string_view get_string_view(const char (& arr)[Sz]) noexcept {
|
||||
return std::string_view(arr, Sz);
|
||||
}
|
||||
|
||||
|
||||
// basic support for binary and type-value properties
|
||||
|
||||
template <typename T, T Type> struct binary_property;
|
||||
template <typename T, T Type, auto Value> struct property;
|
||||
|
||||
template <auto Type> using make_binary_property = binary_property<std::remove_const_t<decltype(Type)>, Type>;
|
||||
template <auto Type, auto Value> using make_property = property<std::remove_const_t<decltype(Type)>, Type, Value>;
|
||||
|
||||
// unicode TS#18 level 1.2 general_category
|
||||
template <uni::detail::binary_prop Property> struct binary_property<uni::detail::binary_prop, Property> {
|
||||
template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
|
||||
return uni::detail::get_binary_prop<Property>(static_cast<char32_t>(c));
|
||||
}
|
||||
};
|
||||
|
||||
// unicode TS#18 level 1.2.2
|
||||
|
||||
enum class property_type {
|
||||
script, script_extension, age, block, unknown
|
||||
};
|
||||
|
||||
// unicode TS#18 level 1.2.2
|
||||
|
||||
template <uni::script Script> struct binary_property<uni::script, Script> {
|
||||
template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
|
||||
return uni::cp_script(c) == Script;
|
||||
}
|
||||
};
|
||||
|
||||
template <uni::script Script> struct property<property_type, property_type::script_extension, Script> {
|
||||
template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
|
||||
for (uni::script sc: uni::cp_script_extensions(c)) {
|
||||
if (sc == Script) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <uni::version Age> struct binary_property<uni::version, Age> {
|
||||
template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
|
||||
return uni::cp_age(c) <= Age;
|
||||
}
|
||||
};
|
||||
|
||||
template <uni::block Block> struct binary_property<uni::block, Block> {
|
||||
template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
|
||||
return uni::cp_block(c) == Block;
|
||||
}
|
||||
};
|
||||
|
||||
// nonbinary properties
|
||||
|
||||
template <typename = void> // Make it always a template as propnamecomp isn't defined yet
|
||||
constexpr property_type property_type_from_name(std::string_view str) noexcept {
|
||||
using namespace std::string_view_literals;
|
||||
if (uni::detail::propnamecomp(str, "script"sv) == 0 || uni::detail::propnamecomp(str, "sc"sv) == 0) {
|
||||
return property_type::script;
|
||||
} else if (uni::detail::propnamecomp(str, "script_extension"sv) == 0 || uni::detail::propnamecomp(str, "scx"sv) == 0) {
|
||||
return property_type::script_extension;
|
||||
} else if (uni::detail::propnamecomp(str, "age"sv) == 0) {
|
||||
return property_type::age;
|
||||
} else if (uni::detail::propnamecomp(str, "block"sv) == 0) {
|
||||
return property_type::block;
|
||||
} else {
|
||||
return property_type::unknown;
|
||||
}
|
||||
}
|
||||
|
||||
template <property_type Property> struct property_type_builder {
|
||||
template <auto... Value> static constexpr auto get() {
|
||||
return ctll::reject{};
|
||||
}
|
||||
};
|
||||
|
||||
template <auto... Name> struct property_builder {
|
||||
static constexpr char name[sizeof...(Name)]{static_cast<char>(Name)...};
|
||||
static constexpr property_type type = property_type_from_name(get_string_view(name));
|
||||
|
||||
using helper = property_type_builder<type>;
|
||||
|
||||
template <auto... Value> static constexpr auto get() {
|
||||
return helper::template get<Value...>();
|
||||
}
|
||||
};
|
||||
|
||||
// unicode TS#18 level 1.2.2 script support
|
||||
|
||||
template <> struct property_type_builder<property_type::script> {
|
||||
template <auto... Value> static constexpr auto get() {
|
||||
constexpr char value[sizeof...(Value)]{static_cast<char>(Value)...};
|
||||
constexpr auto sc = uni::detail::script_from_string(get_string_view(value));
|
||||
if constexpr (uni::detail::is_unknown(sc)) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return make_binary_property<sc>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct property_type_builder<property_type::script_extension> {
|
||||
template <auto... Value> static constexpr auto get() {
|
||||
constexpr char value[sizeof...(Value)]{static_cast<char>(Value)...};
|
||||
constexpr auto sc = uni::detail::script_from_string(get_string_view(value));
|
||||
if constexpr (uni::detail::is_unknown(sc)) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return make_property<property_type::script_extension, sc>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct property_type_builder<property_type::age> {
|
||||
template <auto... Value> static constexpr auto get() {
|
||||
constexpr char value[sizeof...(Value)]{static_cast<char>(Value)...};
|
||||
constexpr auto age = uni::detail::age_from_string(get_string_view(value));
|
||||
if constexpr (uni::detail::is_unassigned(age)) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return make_binary_property<age>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct property_type_builder<property_type::block> {
|
||||
template <auto... Value> static constexpr auto get() {
|
||||
constexpr char value[sizeof...(Value)]{static_cast<char>(Value)...};
|
||||
constexpr auto block = uni::detail::block_from_string(get_string_view(value));
|
||||
if constexpr (uni::detail::is_unknown(block)) {
|
||||
return ctll::reject{};
|
||||
} else {
|
||||
return make_binary_property<block>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,567 @@
|
|||
#ifndef CTRE__EVALUATION__HPP
|
||||
#define CTRE__EVALUATION__HPP
|
||||
|
||||
#include "flags_and_modes.hpp"
|
||||
#include "atoms.hpp"
|
||||
#include "atoms_unicode.hpp"
|
||||
#include "starts_with_anchor.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "return_type.hpp"
|
||||
#include "find_captures.hpp"
|
||||
#include "first.hpp"
|
||||
#ifndef CTRE_IN_A_MODULE
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
// remove me when MSVC fix the constexpr bug
|
||||
#ifdef _MSC_VER
|
||||
#ifndef CTRE_MSVC_GREEDY_WORKAROUND
|
||||
#define CTRE_MSVC_GREEDY_WORKAROUND
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace ctre {
|
||||
|
||||
template <size_t Limit> constexpr CTRE_FORCE_INLINE bool less_than_or_infinite([[maybe_unused]] size_t i) noexcept {
|
||||
if constexpr (Limit == 0) {
|
||||
// infinite
|
||||
return true;
|
||||
} else {
|
||||
return i < Limit;
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t Limit> constexpr CTRE_FORCE_INLINE bool less_than([[maybe_unused]] size_t i) noexcept {
|
||||
if constexpr (Limit == 0) {
|
||||
// infinite
|
||||
return false;
|
||||
} else {
|
||||
return i < Limit;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool is_bidirectional(const std::bidirectional_iterator_tag &) { return true; }
|
||||
constexpr bool is_bidirectional(...) { return false; }
|
||||
|
||||
// sink for making the errors shorter
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R, ...) noexcept {
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
// if we found "accept" object on stack => ACCEPT
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R captures, ctll::list<accept>) noexcept {
|
||||
return captures.matched();
|
||||
}
|
||||
|
||||
// if we found "reject" object on stack => REJECT
|
||||
template <typename R, typename... Rest, typename BeginIterator, typename Iterator, typename EndIterator>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R, ctll::list<reject, Rest...>) noexcept {
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
// mark start of outer capture
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<start_mark, Tail...>) noexcept {
|
||||
return evaluate(begin, current, last, f, captures.set_start_mark(current), ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// mark end of outer capture
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<end_mark, Tail...>) noexcept {
|
||||
return evaluate(begin, current, last, f, captures.set_end_mark(current), ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// mark end of cycle
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator current, const EndIterator, [[maybe_unused]] const flags & f, R captures, ctll::list<end_cycle_mark>) noexcept {
|
||||
if (cannot_be_empty_match(f)) {
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
return captures.set_end_mark(current).matched();
|
||||
}
|
||||
|
||||
// matching everything which behave as a one character matcher
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename CharacterLike, typename... Tail, typename = std::enable_if_t<(MatchesCharacter<CharacterLike>::template value<decltype(*std::declval<Iterator>())>)>>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<CharacterLike, Tail...>) noexcept {
|
||||
if (current == last) return not_matched;
|
||||
if (!CharacterLike::match_char(*current, f)) return not_matched;
|
||||
|
||||
return evaluate(begin, ++current, last, consumed_something(f), captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<any, Tail...>) noexcept {
|
||||
if (current == last) return not_matched;
|
||||
|
||||
if (multiline_mode(f)) {
|
||||
// TODO add support for different line ending and unicode (in a future unicode mode)
|
||||
if (*current == '\n') return not_matched;
|
||||
}
|
||||
return evaluate(begin, ++current, last, consumed_something(f), captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// matching strings in patterns
|
||||
template <auto... String, typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE bool match_string([[maybe_unused]] Iterator & current, [[maybe_unused]] const EndIterator last, [[maybe_unused]] const flags & f) {
|
||||
return ((current != last && character<String>::match_char(*current++, f)) && ... && true);
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, auto... String, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<string<String...>, Tail...>) noexcept {
|
||||
if (!match_string<String...>(current, last, f)) {
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
return evaluate(begin, current, last, consumed_something(f, sizeof...(String) > 0), captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// matching select in patterns
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename HeadOptions, typename... TailOptions, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<select<HeadOptions, TailOptions...>, Tail...>) noexcept {
|
||||
if (auto r = evaluate(begin, current, last, f, captures, ctll::list<HeadOptions, Tail...>())) {
|
||||
return r;
|
||||
} else {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<select<TailOptions...>, Tail...>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R, ctll::list<select<>, Tail...>) noexcept {
|
||||
// no previous option was matched => REJECT
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
// matching sequence in patterns
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename HeadContent, typename... TailContent, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<sequence<HeadContent, TailContent...>, Tail...>) noexcept {
|
||||
if constexpr (sizeof...(TailContent) > 0) {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<HeadContent, sequence<TailContent...>, Tail...>());
|
||||
} else {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<HeadContent, Tail...>());
|
||||
}
|
||||
}
|
||||
|
||||
// matching empty in patterns
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<empty, Tail...>) noexcept {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// matching asserts
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_subject_begin, Tail...>) noexcept {
|
||||
if (begin != current) {
|
||||
return not_matched;
|
||||
}
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_subject_end, Tail...>) noexcept {
|
||||
if (last != current) {
|
||||
return not_matched;
|
||||
}
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_subject_end_line, Tail...>) noexcept {
|
||||
if (multiline_mode(f)) {
|
||||
if (last == current) {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
} else if (*current == '\n' && std::next(current) == last) {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
} else {
|
||||
return not_matched;
|
||||
}
|
||||
} else {
|
||||
if (last != current) {
|
||||
return not_matched;
|
||||
}
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_line_begin, Tail...>) noexcept {
|
||||
if (multiline_mode(f)) {
|
||||
if (begin == current) {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
} else if (*std::prev(current) == '\n') {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
} else {
|
||||
return not_matched;
|
||||
}
|
||||
} else {
|
||||
if (begin != current) {
|
||||
return not_matched;
|
||||
}
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_line_end, Tail...>) noexcept {
|
||||
if (multiline_mode(f)) {
|
||||
if (last == current) {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
} else if (*current == '\n') {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
} else {
|
||||
return not_matched;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO properly match line end
|
||||
if (last != current) {
|
||||
return not_matched;
|
||||
}
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// matching boundary
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename CharacterLike, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<boundary<CharacterLike>, Tail...>) noexcept {
|
||||
|
||||
// reason why I need bidirectional iterators or some clever hack
|
||||
bool before = false;
|
||||
bool after = false;
|
||||
|
||||
static_assert(is_bidirectional(typename std::iterator_traits<Iterator>::iterator_category{}), "To use boundary in regex you need to provide bidirectional iterator or range.");
|
||||
|
||||
if (last != current) {
|
||||
after = CharacterLike::match_char(*current, f);
|
||||
}
|
||||
if (begin != current) {
|
||||
before = CharacterLike::match_char(*std::prev(current), f);
|
||||
}
|
||||
|
||||
if (before == after) return not_matched;
|
||||
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// matching not_boundary
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename CharacterLike, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<not_boundary<CharacterLike>, Tail...>) noexcept {
|
||||
|
||||
// reason why I need bidirectional iterators or some clever hack
|
||||
bool before = false;
|
||||
bool after = false;
|
||||
|
||||
static_assert(is_bidirectional(typename std::iterator_traits<Iterator>::iterator_category{}), "To use boundary in regex you need to provide bidirectional iterator or range.");
|
||||
|
||||
if (last != current) {
|
||||
after = CharacterLike::match_char(*current, f);
|
||||
}
|
||||
if (begin != current) {
|
||||
before = CharacterLike::match_char(*std::prev(current), f);
|
||||
}
|
||||
|
||||
if (before != after) return not_matched;
|
||||
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// lazy repeat
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<lazy_repeat<A,B,Content...>, Tail...>) noexcept {
|
||||
|
||||
if constexpr (B != 0 && A > B) {
|
||||
return not_matched;
|
||||
} else {
|
||||
const Iterator backup_current = current;
|
||||
|
||||
size_t i{0};
|
||||
|
||||
while (less_than<A>(i)) {
|
||||
auto outer_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>());
|
||||
|
||||
if (!outer_result) return not_matched;
|
||||
|
||||
captures = outer_result.unmatch();
|
||||
current = outer_result.get_end_position();
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (auto outer_result = evaluate(begin, current, last, consumed_something(f, backup_current != current), captures, ctll::list<Tail...>())) {
|
||||
return outer_result;
|
||||
}
|
||||
|
||||
while (less_than_or_infinite<B>(i)) {
|
||||
auto inner_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>());
|
||||
|
||||
if (!inner_result) return not_matched;
|
||||
|
||||
auto outer_result = evaluate(begin, inner_result.get_end_position(), last, consumed_something(f), inner_result.unmatch(), ctll::list<Tail...>());
|
||||
|
||||
if (outer_result) {
|
||||
return outer_result;
|
||||
}
|
||||
|
||||
captures = inner_result.unmatch();
|
||||
current = inner_result.get_end_position();
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
// rest of regex
|
||||
return evaluate(begin, current, last, consumed_something(f), captures, ctll::list<Tail...>());
|
||||
}
|
||||
}
|
||||
|
||||
// possessive repeat
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<possessive_repeat<A,B,Content...>, Tail...>) noexcept {
|
||||
|
||||
if constexpr ((B != 0) && (A > B)) {
|
||||
return not_matched;
|
||||
} else {
|
||||
const auto backup_current = current;
|
||||
|
||||
for (size_t i{0}; less_than_or_infinite<B>(i); ++i) {
|
||||
// try as many of inner as possible and then try outer once
|
||||
auto inner_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>());
|
||||
|
||||
if (!inner_result) {
|
||||
if (!less_than<A>(i)) break;
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
captures = inner_result.unmatch();
|
||||
current = inner_result.get_end_position();
|
||||
}
|
||||
|
||||
return evaluate(begin, current, last, consumed_something(f, backup_current != current), captures, ctll::list<Tail...>());
|
||||
}
|
||||
}
|
||||
|
||||
// (gready) repeat
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail>
|
||||
#ifdef CTRE_MSVC_GREEDY_WORKAROUND
|
||||
constexpr inline void evaluate_recursive(R & result, size_t i, const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<repeat<A,B,Content...>, Tail...> stack) noexcept {
|
||||
#else
|
||||
constexpr inline R evaluate_recursive(size_t i, const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<repeat<A,B,Content...>, Tail...> stack) noexcept {
|
||||
#endif
|
||||
if (less_than_or_infinite<B>(i)) {
|
||||
|
||||
// a*ab
|
||||
// aab
|
||||
|
||||
if (auto inner_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>())) {
|
||||
// TODO MSVC issue:
|
||||
// if I uncomment this return it will not fail in constexpr (but the matching result will not be correct)
|
||||
// return inner_result
|
||||
// I tried to add all constructors to R but without any success
|
||||
auto tmp_current = current;
|
||||
tmp_current = inner_result.get_end_position();
|
||||
#ifdef CTRE_MSVC_GREEDY_WORKAROUND
|
||||
evaluate_recursive(result, i+1, begin, tmp_current, last, f, inner_result.unmatch(), stack);
|
||||
if (result) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (auto rec_result = evaluate_recursive(i+1, begin, tmp_current, last, f, inner_result.unmatch(), stack)) {
|
||||
return rec_result;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef CTRE_MSVC_GREEDY_WORKAROUND
|
||||
result = evaluate(begin, current, last, consumed_something(f), captures, ctll::list<Tail...>());
|
||||
#else
|
||||
return evaluate(begin, current, last, consumed_something(f), captures, ctll::list<Tail...>());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
// (greedy) repeat
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, [[maybe_unused]] ctll::list<repeat<A,B,Content...>, Tail...> stack) {
|
||||
|
||||
if constexpr ((B != 0) && (A > B)) {
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
#ifndef CTRE_DISABLE_GREEDY_OPT
|
||||
else if constexpr (!collides(calculate_first(Content{}...), calculate_first(Tail{}...))) {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<possessive_repeat<A,B,Content...>, Tail...>());
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
// A..B
|
||||
size_t i{0};
|
||||
while (less_than<A>(i)) {
|
||||
auto inner_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>());
|
||||
|
||||
if (!inner_result) return not_matched;
|
||||
|
||||
captures = inner_result.unmatch();
|
||||
current = inner_result.get_end_position();
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
#ifdef CTRE_MSVC_GREEDY_WORKAROUND
|
||||
R result;
|
||||
evaluate_recursive(result, i, begin, current, last, f, captures, stack);
|
||||
return result;
|
||||
#else
|
||||
return evaluate_recursive(i, begin, current, last, f, captures, stack);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// capture (numeric ID)
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t Id, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<capture<Id, Content...>, Tail...>) noexcept {
|
||||
return evaluate(begin, current, last, f, captures.template start_capture<Id>(current), ctll::list<sequence<Content...>, numeric_mark<Id>, Tail...>());
|
||||
}
|
||||
|
||||
// capture end mark (numeric and string ID)
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t Id, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<numeric_mark<Id>, Tail...>) noexcept {
|
||||
return evaluate(begin, current, last, f, captures.template end_capture<Id>(current), ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
// capture (string ID)
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t Id, typename Name, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<capture_with_name<Id, Name, Content...>, Tail...>) noexcept {
|
||||
return evaluate(begin, current, last, f, captures.template start_capture<Id>(current), ctll::list<sequence<Content...>, numeric_mark<Id>, Tail...>());
|
||||
}
|
||||
|
||||
// backreference support (match agains content of iterators)
|
||||
template <typename Iterator> struct string_match {
|
||||
Iterator position;
|
||||
bool match;
|
||||
};
|
||||
|
||||
template <typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE string_match<Iterator> match_against_range(Iterator current, const EndIterator last, Iterator range_current, const Iterator range_end, flags) noexcept {
|
||||
while (last != current && range_end != range_current) {
|
||||
if (*current == *range_current) {
|
||||
current++;
|
||||
range_current++;
|
||||
} else {
|
||||
return {current, false};
|
||||
}
|
||||
}
|
||||
return {current, range_current == range_end};
|
||||
}
|
||||
|
||||
// backreference with name
|
||||
template <typename R, typename Id, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<back_reference_with_name<Id>, Tail...>) noexcept {
|
||||
|
||||
if (const auto ref = captures.template get<Id>()) {
|
||||
if (auto result = match_against_range(current, last, ref.begin(), ref.end(), f); result.match) {
|
||||
return evaluate(begin, result.position, last, consumed_something(f, ref.begin() != ref.end()), captures, ctll::list<Tail...>());
|
||||
}
|
||||
}
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
// backreference
|
||||
template <typename R, size_t Id, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<back_reference<Id>, Tail...>) noexcept {
|
||||
|
||||
if (const auto ref = captures.template get<Id>()) {
|
||||
if (auto result = match_against_range(current, last, ref.begin(), ref.end(), f); result.match) {
|
||||
return evaluate(begin, result.position, last, consumed_something(f, ref.begin() != ref.end()), captures, ctll::list<Tail...>());
|
||||
}
|
||||
}
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
// end of lookahead
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R captures, ctll::list<end_lookahead_mark>) noexcept {
|
||||
// TODO check interaction with non-empty flag
|
||||
return captures.matched();
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R captures, ctll::list<end_lookbehind_mark>) noexcept {
|
||||
// TODO check interaction with non-empty flag
|
||||
return captures.matched();
|
||||
}
|
||||
|
||||
// lookahead positive
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<lookahead_positive<Content...>, Tail...>) noexcept {
|
||||
|
||||
if (auto lookahead_result = evaluate(begin, current, last, f, captures, ctll::list<sequence<Content...>, end_lookahead_mark>())) {
|
||||
captures = lookahead_result.unmatch();
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
} else {
|
||||
return not_matched;
|
||||
}
|
||||
}
|
||||
|
||||
// lookahead negative
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<lookahead_negative<Content...>, Tail...>) noexcept {
|
||||
|
||||
if (auto lookahead_result = evaluate(begin, current, last, f, captures, ctll::list<sequence<Content...>, end_lookahead_mark>())) {
|
||||
return not_matched;
|
||||
} else {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
}
|
||||
|
||||
// lookbehind positive
|
||||
constexpr bool is_at_least_bidirectional(std::input_iterator_tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool is_at_least_bidirectional(std::bidirectional_iterator_tag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<lookbehind_positive<Content...>, Tail...>) noexcept {
|
||||
static_assert(is_at_least_bidirectional(typename std::iterator_traits<Iterator>::iterator_category{}), "to use lookbehind you must provide bi-directional iterator");
|
||||
|
||||
if (auto lookbehind_result = evaluate(std::make_reverse_iterator(last), std::make_reverse_iterator(current), std::make_reverse_iterator(begin), f, captures, ctll::list<sequence<Content...>, end_lookbehind_mark>())) {
|
||||
captures = lookbehind_result.unmatch();
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
} else {
|
||||
return not_matched;
|
||||
}
|
||||
}
|
||||
|
||||
// lookbehind negative
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<lookbehind_negative<Content...>, Tail...>) noexcept {
|
||||
static_assert(is_at_least_bidirectional(typename std::iterator_traits<Iterator>::iterator_category{}), "to use negative lookbehind you must provide bi-directional iterator");
|
||||
|
||||
if (auto lookbehind_result = evaluate(std::make_reverse_iterator(last), std::make_reverse_iterator(current), std::make_reverse_iterator(begin), f, captures, ctll::list<sequence<Content...>, end_lookbehind_mark>())) {
|
||||
return not_matched;
|
||||
} else {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename...> constexpr auto dependent_false = false;
|
||||
|
||||
// atomic_group<...> is just transformation to possessive_repeat<1,1,...>
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<atomic_group<Content...>, Tail...>) noexcept {
|
||||
return evaluate(begin, current, last, f, captures, ctll::list<possessive_repeat<1,1,Content...>, Tail...>{});
|
||||
}
|
||||
|
||||
// switching modes
|
||||
template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename Mode, typename... Tail>
|
||||
constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<mode_switch<Mode>, Tail...>) noexcept {
|
||||
return evaluate(begin, current, last, f + Mode{}, captures, ctll::list<Tail...>());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,125 @@
|
|||
#ifndef CTRE__FIND_CAPTURES__HPP
|
||||
#define CTRE__FIND_CAPTURES__HPP
|
||||
|
||||
#include "atoms_characters.hpp"
|
||||
#include "atoms_unicode.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "return_type.hpp"
|
||||
|
||||
namespace ctre {
|
||||
|
||||
CTRE_EXPORT template <typename Pattern> constexpr auto find_captures(Pattern) noexcept {
|
||||
return find_captures(ctll::list<Pattern>(), ctll::list<>());
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Output> constexpr auto find_captures(ctll::list<>, ctll::list<Output...> output) noexcept {
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CTRE_EXPORT template <auto... String, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<string<String...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Options, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<select<Options...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Options..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<optional<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lazy_optional<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<sequence<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<empty, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
CTRE_EXPORT template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<assert_subject_begin, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
CTRE_EXPORT template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<assert_subject_end, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
// , typename = std::enable_if_t<(MatchesCharacter<CharacterLike>::template value<char>)
|
||||
CTRE_EXPORT template <typename CharacterLike, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<CharacterLike, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<plus<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<star<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <size_t A, size_t B, typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<repeat<A,B,Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lazy_plus<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lazy_star<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <size_t A, size_t B, typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lazy_repeat<A,B,Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<possessive_plus<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<possessive_star<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
CTRE_EXPORT template <size_t A, size_t B, typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<possessive_repeat<A,B,Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lookahead_positive<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
CTRE_EXPORT template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lookahead_negative<Content...>, Tail...>, Output output) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), output);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
CTRE_EXPORT template <size_t Id, typename... Content, typename... Tail, typename... Output> constexpr auto find_captures(ctll::list<capture<Id,Content...>, Tail...>, ctll::list<Output...>) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id>>());
|
||||
}
|
||||
|
||||
|
||||
CTRE_EXPORT template <size_t Id, typename Name, typename... Content, typename... Tail, typename... Output> constexpr auto find_captures(ctll::list<capture_with_name<Id,Name,Content...>, Tail...>, ctll::list<Output...>) noexcept {
|
||||
return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id, Name>>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,554 @@
|
|||
#ifndef CTRE__FIRST__HPP
|
||||
#define CTRE__FIRST__HPP
|
||||
|
||||
#include "atoms.hpp"
|
||||
#include "atoms_unicode.hpp"
|
||||
|
||||
namespace ctre {
|
||||
|
||||
struct can_be_anything {};
|
||||
|
||||
|
||||
template <typename... Content>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<>) noexcept {
|
||||
return l;
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<accept, Tail...>) noexcept {
|
||||
return l;
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<end_mark, Tail...>) noexcept {
|
||||
return l;
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<end_cycle_mark, Tail...>) noexcept {
|
||||
return l;
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<end_lookahead_mark, Tail...>) noexcept {
|
||||
return l;
|
||||
}
|
||||
|
||||
template <typename... Content, size_t Id, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<numeric_mark<Id>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Tail...>{});
|
||||
}
|
||||
|
||||
// empty
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<empty, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Tail...>{});
|
||||
}
|
||||
|
||||
// boundary
|
||||
template <typename... Content, typename CharLike, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<boundary<CharLike>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Tail...>{});
|
||||
}
|
||||
|
||||
// asserts
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<assert_subject_begin, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Tail...>{});
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<assert_subject_end, Tail...>) noexcept {
|
||||
return l;
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<assert_subject_end_line, Tail...>) noexcept {
|
||||
// FIXME allow endline here
|
||||
return l;
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<assert_line_begin, Tail...>) noexcept {
|
||||
// FIXME line begin is a bit different than subject begin
|
||||
return first(l, ctll::list<Tail...>{});
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<assert_line_end, Tail...>) noexcept {
|
||||
// FIXME line end is a bit different than subject begin
|
||||
return l;
|
||||
}
|
||||
|
||||
// sequence
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<sequence<Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// atomic group
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<atomic_group<Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<possessive_repeat<1, 1, Seq...>, Tail...>{});
|
||||
}
|
||||
|
||||
// plus
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<plus<Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// lazy_plus
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_plus<Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// possessive_plus
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<possessive_plus<Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// star
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<star<Seq...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// lazy_star
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_star<Seq...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// possessive_star
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<possessive_star<Seq...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// lazy_repeat
|
||||
template <typename... Content, size_t A, size_t B, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_repeat<A, B, Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
template <typename... Content, size_t B, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_repeat<0, B, Seq...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// possessive_repeat
|
||||
template <typename... Content, size_t A, size_t B, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<possessive_repeat<A, B, Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
template <typename... Content, size_t B, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<possessive_repeat<0, B, Seq...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// repeat
|
||||
template <typename... Content, size_t A, size_t B, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<repeat<A, B, Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
template <typename... Content, size_t B, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<repeat<0, B, Seq...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// lookahead_positive
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<lookahead_positive<Seq...>, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
// lookbehind_negative TODO fixme
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<lookbehind_negative<Seq...>, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
// lookbehind_positive
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<lookbehind_positive<Seq...>, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
// lookahead_negative TODO fixme
|
||||
template <typename... Content, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<lookahead_negative<Seq...>, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
// capture
|
||||
template <typename... Content, size_t Id, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<capture<Id, Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
template <typename... Content, size_t Id, typename Name, typename... Seq, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<capture_with_name<Id, Name, Seq...>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Seq..., Tail...>{});
|
||||
}
|
||||
|
||||
// backreference
|
||||
template <typename... Content, size_t Id, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<back_reference<Id>, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
template <typename... Content, typename Name, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<back_reference_with_name<Name>, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
|
||||
// string First extraction
|
||||
template <typename... Content, auto First, auto... String, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<string<First, String...>, Tail...>) noexcept {
|
||||
return ctll::list<Content..., character<First>>{};
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<string<>, Tail...>) noexcept {
|
||||
return first(l, ctll::list<Tail...>{});
|
||||
}
|
||||
|
||||
// optional
|
||||
template <typename... Content, typename... Opt, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<optional<Opt...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<Opt..., Tail...>{}), ctll::list<Tail...>{});
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Opt, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_optional<Opt...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<Opt..., Tail...>{}), ctll::list<Tail...>{});
|
||||
}
|
||||
|
||||
// select (alternation)
|
||||
template <typename... Content, typename SHead, typename... STail, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<select<SHead, STail...>, Tail...>) noexcept {
|
||||
return first(first(l, ctll::list<SHead, Tail...>{}), ctll::list<select<STail...>, Tail...>{});
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...> l, ctll::list<select<>, Tail...>) noexcept {
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
// unicode property => anything
|
||||
template <typename... Content, typename PropertyType, PropertyType Property, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<ctre::binary_property<PropertyType, Property>, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
template <typename... Content, typename PropertyType, PropertyType Property, auto Value, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<ctre::property<PropertyType, Property, Value>, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
// characters / sets
|
||||
|
||||
template <typename... Content, auto V, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<character<V>, Tail...>) noexcept {
|
||||
return ctll::list<Content..., character<V>>{};
|
||||
}
|
||||
|
||||
template <typename... Content, auto... Values, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<enumeration<Values...>, Tail...>) noexcept {
|
||||
return ctll::list<Content..., character<Values>...>{};
|
||||
}
|
||||
|
||||
template <typename... Content, typename... SetContent, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<set<SetContent...>, Tail...>) noexcept {
|
||||
return ctll::list<Content..., SetContent...>{};
|
||||
}
|
||||
|
||||
template <typename... Content, auto A, auto B, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<char_range<A,B>, Tail...>) noexcept {
|
||||
return ctll::list<Content..., char_range<A,B>>{};
|
||||
}
|
||||
|
||||
template <typename... Content, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<any, Tail...>) noexcept {
|
||||
return ctll::list<can_be_anything>{};
|
||||
}
|
||||
|
||||
// negative
|
||||
template <typename... Content, typename... SetContent, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<negate<SetContent...>, Tail...>) noexcept {
|
||||
return ctll::list<Content..., negative_set<SetContent...>>{};
|
||||
}
|
||||
|
||||
template <typename... Content, typename... SetContent, typename... Tail>
|
||||
constexpr auto first(ctll::list<Content...>, ctll::list<negative_set<SetContent...>, Tail...>) noexcept {
|
||||
return ctll::list<Content..., negative_set<SetContent...>>{};
|
||||
}
|
||||
|
||||
|
||||
// user facing interface
|
||||
template <typename... Content> constexpr auto calculate_first(Content...) noexcept {
|
||||
return first(ctll::list<>{}, ctll::list<Content...>{});
|
||||
}
|
||||
|
||||
|
||||
// calculate mutual exclusivity
|
||||
template <typename... Content> constexpr size_t calculate_size_of_first(ctre::negative_set<Content...>) {
|
||||
return 1 + calculate_size_of_first(ctre::set<Content...>{});
|
||||
}
|
||||
|
||||
template <auto... V> constexpr size_t calculate_size_of_first(ctre::enumeration<V...>) {
|
||||
return sizeof...(V);
|
||||
}
|
||||
|
||||
constexpr size_t calculate_size_of_first(...) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename... Content> constexpr size_t calculate_size_of_first(ctll::list<Content...>) {
|
||||
return (calculate_size_of_first(Content{}) + ... + 0);
|
||||
}
|
||||
|
||||
template <typename... Content> constexpr size_t calculate_size_of_first(ctre::set<Content...>) {
|
||||
return (calculate_size_of_first(Content{}) + ... + 0);
|
||||
}
|
||||
|
||||
template <auto A, typename CB> constexpr int64_t negative_helper(ctre::character<A>, CB & cb, int64_t start) {
|
||||
if (A != (std::numeric_limits<int64_t>::min)()) {
|
||||
if (start < A) {
|
||||
cb(start, A-1);
|
||||
}
|
||||
}
|
||||
if (A != (std::numeric_limits<int64_t>::max)()) {
|
||||
return A+1;
|
||||
} else {
|
||||
return A;
|
||||
}
|
||||
}
|
||||
|
||||
template <auto A, auto B, typename CB> constexpr int64_t negative_helper(ctre::char_range<A,B>, CB & cb, int64_t start) {
|
||||
if (A != (std::numeric_limits<int64_t>::min)()) {
|
||||
if (start < A) {
|
||||
cb(start, A-1);
|
||||
}
|
||||
}
|
||||
if (B != (std::numeric_limits<int64_t>::max)()) {
|
||||
return B+1;
|
||||
} else {
|
||||
return B;
|
||||
}
|
||||
}
|
||||
|
||||
template <auto Head, auto... Tail, typename CB> constexpr int64_t negative_helper(ctre::enumeration<Head, Tail...>, CB & cb, int64_t start) {
|
||||
int64_t nstart = negative_helper(ctre::character<Head>{}, cb, start);
|
||||
return negative_helper(ctre::enumeration<Tail...>{}, cb, nstart);
|
||||
}
|
||||
|
||||
template <typename CB> constexpr int64_t negative_helper(ctre::enumeration<>, CB &, int64_t start) {
|
||||
return start;
|
||||
}
|
||||
|
||||
template <typename CB> constexpr int64_t negative_helper(ctre::set<>, CB &, int64_t start) {
|
||||
return start;
|
||||
}
|
||||
|
||||
template <typename PropertyType, PropertyType Property, typename CB>
|
||||
constexpr auto negative_helper(ctre::binary_property<PropertyType, Property>, CB &&, int64_t start) {
|
||||
return start;
|
||||
}
|
||||
|
||||
template <typename PropertyType, PropertyType Property, auto Value, typename CB>
|
||||
constexpr auto negative_helper(ctre::property<PropertyType, Property, Value>, CB &&, int64_t start) {
|
||||
return start;
|
||||
}
|
||||
|
||||
template <typename Head, typename... Rest, typename CB> constexpr int64_t negative_helper(ctre::set<Head, Rest...>, CB & cb, int64_t start) {
|
||||
start = negative_helper(Head{}, cb, start);
|
||||
return negative_helper(ctre::set<Rest...>{}, cb, start);
|
||||
}
|
||||
|
||||
template <typename Head, typename... Rest, typename CB> constexpr void negative_helper(ctre::negative_set<Head, Rest...>, CB && cb, int64_t start = (std::numeric_limits<int64_t>::min)()) {
|
||||
start = negative_helper(Head{}, cb, start);
|
||||
negative_helper(ctre::negative_set<Rest...>{}, std::forward<CB>(cb), start);
|
||||
}
|
||||
|
||||
template <typename CB> constexpr void negative_helper(ctre::negative_set<>, CB && cb, int64_t start = (std::numeric_limits<int64_t>::min)()) {
|
||||
if (start < (std::numeric_limits<int64_t>::max)()) {
|
||||
cb(start, (std::numeric_limits<int64_t>::max)());
|
||||
}
|
||||
}
|
||||
|
||||
// simple fixed set
|
||||
// TODO: this needs some optimizations
|
||||
template <size_t Capacity> class point_set {
|
||||
struct point {
|
||||
int64_t low{};
|
||||
int64_t high{};
|
||||
constexpr bool operator<(const point & rhs) const {
|
||||
return low < rhs.low;
|
||||
}
|
||||
constexpr point() { }
|
||||
constexpr point(int64_t l, int64_t h): low{l}, high{h} { }
|
||||
};
|
||||
point points[Capacity+1]{};
|
||||
size_t used{0};
|
||||
constexpr point * begin() {
|
||||
return points;
|
||||
}
|
||||
constexpr point * begin() const {
|
||||
return points;
|
||||
}
|
||||
constexpr point * end() {
|
||||
return points + used;
|
||||
}
|
||||
constexpr point * end() const {
|
||||
return points + used;
|
||||
}
|
||||
constexpr point * lower_bound(point obj) {
|
||||
auto first = begin();
|
||||
auto last = end();
|
||||
auto it = first;
|
||||
auto count = std::distance(first, last);
|
||||
while (count != 0) {
|
||||
it = first;
|
||||
auto step = count / 2;
|
||||
std::advance(it, step);
|
||||
if (*it < obj) {
|
||||
first = ++it;
|
||||
count -= step + 1;
|
||||
} else {
|
||||
count = step;
|
||||
}
|
||||
}
|
||||
return it;
|
||||
}
|
||||
constexpr point * insert_point(int64_t position, int64_t other) {
|
||||
point obj{position, other};
|
||||
auto it = lower_bound(obj);
|
||||
if (it == end()) {
|
||||
*it = obj;
|
||||
used++;
|
||||
return it;
|
||||
} else {
|
||||
auto out = it;
|
||||
auto e = end();
|
||||
while (it != e) {
|
||||
auto tmp = *it;
|
||||
*it = obj;
|
||||
obj = tmp;
|
||||
//std::swap(*it, obj);
|
||||
it++;
|
||||
}
|
||||
auto tmp = *it;
|
||||
*it = obj;
|
||||
obj = tmp;
|
||||
//std::swap(*it, obj);
|
||||
|
||||
used++;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
public:
|
||||
constexpr point_set() { }
|
||||
constexpr void insert(int64_t low, int64_t high) {
|
||||
insert_point(low, high);
|
||||
//insert_point(high, low);
|
||||
}
|
||||
constexpr bool check(int64_t low, int64_t high) {
|
||||
for (const auto & r: *this) {
|
||||
if (r.low <= low && low <= r.high) {
|
||||
return true;
|
||||
} else if (r.low <= high && high <= r.high) {
|
||||
return true;
|
||||
} else if (low <= r.low && r.low <= high) {
|
||||
return true;
|
||||
} else if (low <= r.high && r.high <= high) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <auto V> constexpr bool check(ctre::character<V>) {
|
||||
return check(V,V);
|
||||
}
|
||||
template <auto A, auto B> constexpr bool check(ctre::char_range<A,B>) {
|
||||
return check(A,B);
|
||||
}
|
||||
constexpr bool check(can_be_anything) {
|
||||
return used > 0;
|
||||
}
|
||||
template <typename PropertyType, PropertyType Property>
|
||||
constexpr bool check(ctre::binary_property<PropertyType, Property>) {
|
||||
return check(can_be_anything{});
|
||||
}
|
||||
|
||||
template <typename PropertyType, PropertyType Property, auto Value>
|
||||
constexpr bool check(ctre::property<PropertyType, Property, Value>) {
|
||||
return check(can_be_anything{});
|
||||
}
|
||||
template <typename... Content> constexpr bool check(ctre::negative_set<Content...> nset) {
|
||||
bool collision = false;
|
||||
negative_helper(nset, [&](int64_t low, int64_t high){
|
||||
collision |= this->check(low, high);
|
||||
});
|
||||
return collision;
|
||||
}
|
||||
template <auto... V> constexpr bool check(ctre::enumeration<V...>) {
|
||||
|
||||
return (check(V,V) || ... || false);
|
||||
}
|
||||
template <typename... Content> constexpr bool check(ctll::list<Content...>) {
|
||||
return (check(Content{}) || ... || false);
|
||||
}
|
||||
template <typename... Content> constexpr bool check(ctre::set<Content...>) {
|
||||
return (check(Content{}) || ... || false);
|
||||
}
|
||||
|
||||
|
||||
template <auto V> constexpr void populate(ctre::character<V>) {
|
||||
insert(V,V);
|
||||
}
|
||||
template <auto A, auto B> constexpr void populate(ctre::char_range<A,B>) {
|
||||
insert(A,B);
|
||||
}
|
||||
constexpr void populate(...) {
|
||||
points[0].low = (std::numeric_limits<int64_t>::min)();
|
||||
points[0].high = (std::numeric_limits<int64_t>::max)();
|
||||
used = 1;
|
||||
}
|
||||
template <typename... Content> constexpr void populate(ctre::negative_set<Content...> nset) {
|
||||
negative_helper(nset, [&](int64_t low, int64_t high){
|
||||
this->insert(low, high);
|
||||
});
|
||||
}
|
||||
template <typename... Content> constexpr void populate(ctre::set<Content...>) {
|
||||
(populate(Content{}), ...);
|
||||
}
|
||||
template <typename... Content> constexpr void populate(ctll::list<Content...>) {
|
||||
(populate(Content{}), ...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... A, typename... B> constexpr bool collides(ctll::list<A...> rhs, ctll::list<B...> lhs) {
|
||||
constexpr size_t capacity = calculate_size_of_first(rhs);
|
||||
|
||||
point_set<capacity> set;
|
||||
set.populate(rhs);
|
||||
|
||||
return set.check(lhs);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,97 @@
|
|||
#ifndef CTRE_V2__CTRE__FLAGS_AND_MODES__HPP
|
||||
#define CTRE_V2__CTRE__FLAGS_AND_MODES__HPP
|
||||
|
||||
namespace ctre {
|
||||
|
||||
struct singleline { };
|
||||
struct multiline { };
|
||||
|
||||
struct case_sensitive { };
|
||||
struct case_insensitive { };
|
||||
|
||||
using ci = case_insensitive;
|
||||
using cs = case_sensitive;
|
||||
|
||||
template <typename... Flags> struct flag_list { };
|
||||
|
||||
struct flags {
|
||||
bool block_empty_match = false;
|
||||
bool multiline = false;
|
||||
bool case_insensitive = false;
|
||||
|
||||
constexpr flags() = default;
|
||||
constexpr flags(const flags &) = default;
|
||||
constexpr flags(flags &&) = default;
|
||||
|
||||
constexpr CTRE_FORCE_INLINE flags(ctre::singleline v) noexcept { set_flag(v); }
|
||||
constexpr CTRE_FORCE_INLINE flags(ctre::multiline v) noexcept { set_flag(v); }
|
||||
constexpr CTRE_FORCE_INLINE flags(ctre::case_sensitive v) noexcept { set_flag(v); }
|
||||
constexpr CTRE_FORCE_INLINE flags(ctre::case_insensitive v) noexcept { set_flag(v); }
|
||||
|
||||
|
||||
template <typename... Args> constexpr CTRE_FORCE_INLINE flags(ctll::list<Args...>) noexcept {
|
||||
(this->set_flag(Args{}), ...);
|
||||
}
|
||||
|
||||
constexpr friend CTRE_FORCE_INLINE auto operator+(flags f, pcre::mode_case_insensitive) noexcept {
|
||||
f.case_insensitive = true;
|
||||
return f;
|
||||
}
|
||||
|
||||
constexpr friend CTRE_FORCE_INLINE auto operator+(flags f, pcre::mode_case_sensitive) noexcept {
|
||||
f.case_insensitive = false;
|
||||
return f;
|
||||
}
|
||||
|
||||
constexpr friend CTRE_FORCE_INLINE auto operator+(flags f, pcre::mode_singleline) noexcept {
|
||||
f.multiline = false;
|
||||
return f;
|
||||
}
|
||||
|
||||
constexpr friend CTRE_FORCE_INLINE auto operator+(flags f, pcre::mode_multiline) noexcept {
|
||||
f.multiline = true;
|
||||
return f;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE void set_flag(ctre::singleline) noexcept {
|
||||
multiline = false;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE void set_flag(ctre::multiline) noexcept {
|
||||
multiline = true;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE void set_flag(ctre::case_insensitive) noexcept {
|
||||
case_insensitive = true;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE void set_flag(ctre::case_sensitive) noexcept {
|
||||
case_insensitive = false;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr CTRE_FORCE_INLINE auto not_empty_match(flags f) {
|
||||
f.block_empty_match = true;
|
||||
return f;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE auto consumed_something(flags f, bool condition = true) {
|
||||
if (condition) f.block_empty_match = false;
|
||||
return f;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE bool cannot_be_empty_match(flags f) {
|
||||
return f.block_empty_match;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE bool multiline_mode(flags f) {
|
||||
return f.multiline;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE bool is_case_insensitive(flags f) {
|
||||
return f.case_insensitive;
|
||||
}
|
||||
|
||||
} // namespace ctre
|
||||
|
||||
#endif
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef CTRE_V2__CTRE__FUNCTIONS__HPP
|
||||
#define CTRE_V2__CTRE__FUNCTIONS__HPP
|
||||
|
||||
#include "../ctll.hpp"
|
||||
#include "pcre_actions.hpp"
|
||||
#include "evaluation.hpp"
|
||||
#include "wrapper.hpp"
|
||||
#include "id.hpp"
|
||||
|
||||
namespace ctre {
|
||||
|
||||
#if !CTRE_CNTTP_COMPILER_CHECK
|
||||
// avoiding CTAD limitation in C++17
|
||||
template <typename CharT, size_t N> class pattern: public ctll::fixed_string<N> {
|
||||
using parent = ctll::fixed_string<N>;
|
||||
public:
|
||||
constexpr pattern(const CharT (&input)[N]) noexcept: parent(input) { }
|
||||
};
|
||||
|
||||
template <typename CharT, size_t N> pattern(const CharT (&)[N]) -> pattern<CharT, N>;
|
||||
|
||||
// for better examples
|
||||
template <typename CharT, size_t N> class fixed_string: public ctll::fixed_string<N> {
|
||||
using parent = ctll::fixed_string<N>;
|
||||
public:
|
||||
constexpr fixed_string(const CharT (&input)[N]) noexcept: parent(input) { }
|
||||
};
|
||||
|
||||
template <typename CharT, size_t N> fixed_string(const CharT (&)[N]) -> fixed_string<CharT, N>;
|
||||
#endif
|
||||
|
||||
#if CTRE_CNTTP_COMPILER_CHECK
|
||||
template <ctll::fixed_string input, typename Modifier = void> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto re() noexcept {
|
||||
constexpr auto _input = input; // workaround for GCC 9 bug 88092
|
||||
#else
|
||||
template <auto & input, typename Modifier = void> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto re() noexcept {
|
||||
constexpr auto & _input = input;
|
||||
#endif
|
||||
|
||||
using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>;
|
||||
static_assert(tmp(), "Regular Expression contains syntax error.");
|
||||
using regex = decltype(front(typename tmp::output_type::stack_type()));
|
||||
return ctre::regular_expression<regex, Modifier, singleline>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef CTRE__ID__HPP
|
||||
#define CTRE__ID__HPP
|
||||
|
||||
#ifndef CTRE_IN_A_MODULE
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace ctre {
|
||||
|
||||
template <auto... Name> struct id {
|
||||
static constexpr auto name = ctll::fixed_string<sizeof...(Name)>{{Name...}};
|
||||
|
||||
friend constexpr auto operator==(id<Name...>, id<Name...>) noexcept -> std::true_type { return {}; }
|
||||
|
||||
template <auto... Other> friend constexpr auto operator==(id<Name...>, id<Other...>) noexcept -> std::false_type { return {}; }
|
||||
|
||||
template <typename T> friend constexpr auto operator==(id<Name...>, T) noexcept -> std::false_type { return {}; }
|
||||
|
||||
template <typename T> friend constexpr auto operator==(T, id<Name...>) noexcept -> std::false_type { return {}; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,196 @@
|
|||
#ifndef CTRE_V2__CTRE__ITERATOR__HPP
|
||||
#define CTRE_V2__CTRE__ITERATOR__HPP
|
||||
|
||||
#include "literals.hpp"
|
||||
#include "wrapper.hpp"
|
||||
#ifndef CTRE_IN_A_MODULE
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
namespace ctre {
|
||||
|
||||
// TODO make proper iterator traits here
|
||||
|
||||
struct regex_end_iterator {
|
||||
constexpr regex_end_iterator() noexcept { }
|
||||
};
|
||||
|
||||
template <typename BeginIterator, typename EndIterator, typename RE, typename ResultIterator = BeginIterator> struct regex_iterator {
|
||||
using value_type = decltype(RE::template exec_with_result_iterator<ResultIterator>(std::declval<BeginIterator>(), std::declval<EndIterator>()));
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using pointer = void;
|
||||
using reference = const value_type &;
|
||||
using difference_type = int;
|
||||
|
||||
BeginIterator orig_begin{};
|
||||
BeginIterator current{};
|
||||
EndIterator end{};
|
||||
value_type current_match{};
|
||||
|
||||
constexpr CTRE_FORCE_INLINE regex_iterator() noexcept = default;
|
||||
constexpr CTRE_FORCE_INLINE regex_iterator(const regex_iterator &) noexcept = default;
|
||||
constexpr CTRE_FORCE_INLINE regex_iterator(regex_iterator &&) noexcept = default;
|
||||
|
||||
constexpr CTRE_FORCE_INLINE regex_iterator(BeginIterator begin, EndIterator last) noexcept: orig_begin{begin}, current{begin}, end{last}, current_match{RE::template exec_with_result_iterator<ResultIterator>(current, last)} {
|
||||
if (current_match) {
|
||||
current = current_match.template get<0>().end();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE regex_iterator & operator=(const regex_iterator &) noexcept = default;
|
||||
constexpr CTRE_FORCE_INLINE regex_iterator & operator=(regex_iterator &&) noexcept = default;
|
||||
|
||||
constexpr CTRE_FORCE_INLINE const value_type & operator*() const noexcept {
|
||||
return current_match;
|
||||
}
|
||||
constexpr CTRE_FORCE_INLINE regex_iterator & operator++() noexcept {
|
||||
if (current == end) {
|
||||
current_match = decltype(current_match){};
|
||||
return *this;
|
||||
}
|
||||
|
||||
current_match = RE::template exec_with_result_iterator<ResultIterator>(orig_begin, current, end);
|
||||
|
||||
if (current_match) {
|
||||
current = current_match.template get<0>().end();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
constexpr CTRE_FORCE_INLINE regex_iterator operator++(int) noexcept {
|
||||
auto previous = *this;
|
||||
this->operator++();
|
||||
return previous;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator==(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current == right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator!=(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return !(left.current == right.current);
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator<(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current < right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator>(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current > right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator<=(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current <= right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator>=(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current >= right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator==(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, regex_end_iterator) noexcept {
|
||||
return !bool(left.current_match);
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator==(regex_end_iterator, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return !bool(right.current_match);
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator!=(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, regex_end_iterator) noexcept {
|
||||
return bool(left.current_match);
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator!=(regex_end_iterator, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return bool(right.current_match);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename BeginIterator, typename EndIterator, typename RE, typename ResultIterator = BeginIterator> struct regex_split_iterator {
|
||||
using value_type = decltype(RE::template exec_with_result_iterator<ResultIterator>(std::declval<BeginIterator>(), std::declval<EndIterator>()));
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using pointer = void;
|
||||
using reference = const value_type &;
|
||||
using difference_type = int;
|
||||
|
||||
BeginIterator orig_begin{};
|
||||
BeginIterator current{};
|
||||
EndIterator end{};
|
||||
value_type current_match{};
|
||||
bool last_match{false};
|
||||
|
||||
constexpr CTRE_FORCE_INLINE void modify_match() {
|
||||
auto tmp = current_match.template get<0>().end();
|
||||
current_match.set_end_mark(current_match.template get<0>().begin());
|
||||
current_match.set_start_mark(current);
|
||||
current = tmp;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE void match_rest() {
|
||||
// the end is there set by search_method
|
||||
current_match.set_start_mark(current);
|
||||
current_match.matched();
|
||||
current = current_match.template get<0>().end();
|
||||
last_match = true;
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE regex_split_iterator() noexcept = default;
|
||||
constexpr CTRE_FORCE_INLINE regex_split_iterator(const regex_split_iterator &) noexcept = default;
|
||||
constexpr CTRE_FORCE_INLINE regex_split_iterator(regex_split_iterator &&) noexcept = default;
|
||||
|
||||
constexpr CTRE_FORCE_INLINE regex_split_iterator(BeginIterator begin, EndIterator last) noexcept: orig_begin{begin}, current{begin}, end{last}, current_match{RE::template exec_with_result_iterator<ResultIterator>(current, last)} {
|
||||
if (current_match) {
|
||||
modify_match();
|
||||
} else {
|
||||
match_rest();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr CTRE_FORCE_INLINE regex_split_iterator & operator=(const regex_split_iterator &) noexcept = default;
|
||||
constexpr CTRE_FORCE_INLINE regex_split_iterator & operator=(regex_split_iterator &&) noexcept = default;
|
||||
|
||||
constexpr CTRE_FORCE_INLINE const value_type & operator*() const noexcept {
|
||||
return current_match;
|
||||
}
|
||||
constexpr CTRE_FORCE_INLINE regex_split_iterator & operator++() noexcept {
|
||||
if (current == end && last_match) {
|
||||
current_match = decltype(current_match){};
|
||||
return *this;
|
||||
}
|
||||
|
||||
current_match = RE::template exec_with_result_iterator<ResultIterator>(orig_begin, current, end);
|
||||
|
||||
if (current_match) {
|
||||
modify_match();
|
||||
} else {
|
||||
match_rest();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
constexpr CTRE_FORCE_INLINE regex_split_iterator operator++(int) noexcept {
|
||||
auto previous = *this;
|
||||
this->operator++();
|
||||
return previous;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator==(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current == right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator!=(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return !(left.current == right.current);
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator<(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current < right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator>(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current > right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator<=(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current <= right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator>=(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return left.current >= right.current;
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator==(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, regex_end_iterator) noexcept {
|
||||
return !bool(left.current_match);
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator==(regex_end_iterator, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return !bool(right.current_match);
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator!=(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, regex_end_iterator) noexcept {
|
||||
return bool(left.current_match);
|
||||
}
|
||||
friend constexpr CTRE_FORCE_INLINE bool operator!=(regex_end_iterator, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
|
||||
return bool(right.current_match);
|
||||
}
|
||||
};
|
||||
|
||||
} // ctre
|
||||
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
#ifndef CTRE_V2__CTRE__LITERALS__HPP
|
||||
#define CTRE_V2__CTRE__LITERALS__HPP
|
||||
|
||||
#include "../ctll.hpp"
|
||||
#include "pcre_actions.hpp"
|
||||
#include "evaluation.hpp"
|
||||
#include "wrapper.hpp"
|
||||
#include "id.hpp"
|
||||
|
||||
#ifndef __EDG__
|
||||
|
||||
namespace ctre {
|
||||
|
||||
// in C++17 (clang & gcc with gnu extension) we need translate character pack into ctll::fixed_string
|
||||
// in C++20 we have `class nontype template parameters`
|
||||
|
||||
#if !CTRE_CNTTP_COMPILER_CHECK
|
||||
template <typename CharT, CharT... input> static inline constexpr auto _fixed_string_reference = ctll::fixed_string< sizeof...(input)>({input...});
|
||||
#endif
|
||||
|
||||
namespace literals {
|
||||
|
||||
// clang and GCC <9 supports LITERALS with packs
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
|
||||
#define CTRE_ENABLE_LITERALS
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _MSVC_LANG
|
||||
#if _MSVC_LANG >= 202002L
|
||||
#define CTRE_ENABLE_LITERALS
|
||||
#endif
|
||||
#else
|
||||
#define CTRE_ENABLE_LITERALS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
// not enable literals
|
||||
#elif defined __GNUC__
|
||||
#if __GNUC__ < 9
|
||||
#define CTRE_ENABLE_LITERALS
|
||||
#elif __GNUC__ >= 10
|
||||
#if !CTRE_CNTTP_COMPILER_CHECK
|
||||
// newer versions of GCC will give error when trying to use GNU extension
|
||||
#else
|
||||
#define CTRE_ENABLE_LITERALS
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CTRE_ENABLE_LITERALS
|
||||
|
||||
// add this when we will have concepts
|
||||
// requires ctll::parser<ctre::pcre, _fixed_string_reference<CharT, charpack...>, ctre::pcre_actions>::template correct_with<pcre_context<>>
|
||||
|
||||
#if !CTRE_CNTTP_COMPILER_CHECK
|
||||
template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre() noexcept {
|
||||
constexpr auto & _input = _fixed_string_reference<CharT, charpack...>;
|
||||
#else
|
||||
template <ctll::fixed_string input> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre() noexcept {
|
||||
constexpr auto _input = input; // workaround for GCC 9 bug 88092
|
||||
#endif
|
||||
using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>;
|
||||
static_assert(tmp(), "Regular Expression contains syntax error.");
|
||||
if constexpr (tmp()) {
|
||||
using re = decltype(front(typename tmp::output_type::stack_type()));
|
||||
return ctre::regular_expression(re());
|
||||
} else {
|
||||
return ctre::regular_expression(reject());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// this will need to be fixed with C++20
|
||||
#if !CTRE_CNTTP_COMPILER_CHECK
|
||||
template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre_id() noexcept {
|
||||
return id<charpack...>();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CTRE_ENABLE_LITERALS
|
||||
|
||||
}
|
||||
|
||||
namespace test_literals {
|
||||
|
||||
#ifdef CTRE_ENABLE_LITERALS
|
||||
|
||||
#if !CTRE_CNTTP_COMPILER_CHECK
|
||||
template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr inline auto operator""_ctre_test() noexcept {
|
||||
constexpr auto & _input = _fixed_string_reference<CharT, charpack...>;
|
||||
#else
|
||||
template <ctll::fixed_string input> CTRE_FLATTEN constexpr inline auto operator""_ctre_test() noexcept {
|
||||
constexpr auto _input = input; // workaround for GCC 9 bug 88092
|
||||
#endif
|
||||
return ctll::parser<ctre::pcre, _input>::template correct_with<>;
|
||||
}
|
||||
|
||||
#if !CTRE_CNTTP_COMPILER_CHECK
|
||||
template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr inline auto operator""_ctre_gen() noexcept {
|
||||
constexpr auto & _input = _fixed_string_reference<CharT, charpack...>;
|
||||
#else
|
||||
template <ctll::fixed_string input> CTRE_FLATTEN constexpr inline auto operator""_ctre_gen() noexcept {
|
||||
constexpr auto _input = input; // workaround for GCC 9 bug 88092
|
||||
#endif
|
||||
using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>;
|
||||
static_assert(tmp(), "Regular Expression contains syntax error.");
|
||||
return typename tmp::output_type::stack_type();
|
||||
}
|
||||
|
||||
|
||||
#if !CTRE_CNTTP_COMPILER_CHECK
|
||||
template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre_syntax() noexcept {
|
||||
constexpr auto & _input = _fixed_string_reference<CharT, charpack...>;
|
||||
#else
|
||||
template <ctll::fixed_string input> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre_syntax() noexcept {
|
||||
constexpr auto _input = input; // workaround for GCC 9 bug 88092
|
||||
#endif
|
||||
return ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template correct_with<pcre_context<>>;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // literals
|
||||
|
||||
} // ctre
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef CTRE_V2__CTRE__OPERATORS__HPP
|
||||
#define CTRE_V2__CTRE__OPERATORS__HPP
|
||||
|
||||
template <typename A, typename B> constexpr auto operator|(ctre::regular_expression<A>, ctre::regular_expression<B>) -> ctre::regular_expression<ctre::select<A,B>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename A, typename B> constexpr auto operator>>(ctre::regular_expression<A>, ctre::regular_expression<B>) -> ctre::regular_expression<ctre::sequence<A,B>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,189 @@
|
|||
backslash={\\}
|
||||
slash={/}
|
||||
dot={.}
|
||||
dolar={$}
|
||||
open={(}
|
||||
close={)}
|
||||
questionmark={?}
|
||||
colon={:}
|
||||
sopen={[}
|
||||
sclose={]}
|
||||
plus={+}
|
||||
star={*}
|
||||
copen={\{}
|
||||
cclose={\}}
|
||||
num={0,1,2,3,4,5,6,7,8,9}
|
||||
comma={\,}
|
||||
pipe={|}
|
||||
caret={^}
|
||||
minus={-}
|
||||
angle_open={<}
|
||||
angle_close={>}
|
||||
equal_sign={=}
|
||||
exclamation_mark={!}
|
||||
doublequote={\"}
|
||||
|
||||
escape_alphanum={b,c,h,i,j,k,l,m,o,q,v,y,z,A,B,C,E,F,G,H,I,J,K,L,M,O,Q,U,V,X,Y,Z,1,2,3,4,5,6,7,8,9}
|
||||
escape_backreference={1,2,3,4,5,6,7,8,9}
|
||||
hexdec={0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,A,B,C,D,E,F}
|
||||
octal={0,1,2,3,4,5,6,7}
|
||||
nonspecial_characters={/,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,0,1,2,3,4,5,6,7,8,9,\,,:,!,=,_,\"}
|
||||
nonspecial_characters_in_class={/,_,+,*,(,),.,$,\{,\},?,!,=,<,>,|,\"}
|
||||
alpha_characters={a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,_}
|
||||
alphanum_characters={a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,0,1,2,3,4,5,6,7,8,9,_}
|
||||
set_control_chars={:,],-}
|
||||
capture_control_chars={<}
|
||||
|
||||
S-><content> | epsilon,[push_empty] | pipe,[push_empty],<opt_content>,[make_alternate]
|
||||
|
||||
opt_content->epsilon,[push_empty]|<content>
|
||||
content-><string>,<content2>
|
||||
content_in_capture-><string_in_capture>,<content2> | epsilon,[push_empty]
|
||||
content_in_capture->pipe,[push_empty],<content_or_empty>,[make_alternate]
|
||||
content_or_empty-><content> | epsilon,[push_empty]
|
||||
|
||||
content2->pipe,<content>,[make_alternate] |pipe,[push_empty],[make_alternate] | epsilon
|
||||
|
||||
string-><atom_repeat>,<string2>
|
||||
string2-><atom_repeat>,<string2>,[make_sequence] | epsilon
|
||||
|
||||
string_in_capture-><atom_repeat_in_capture>,<string2>
|
||||
|
||||
atom_repeat-><atom>,<repeat>
|
||||
|
||||
atom_repeat_in_capture-><atom_in_capture>,<repeat>
|
||||
|
||||
atom-><character>|<asserts>|<preblock>|<character_class>
|
||||
atom_in_capture-><character_in_capture>|<asserts>|<preblock>|<character_class>
|
||||
|
||||
repeat->epsilon | plus,[repeat_plus],<mod>|star,[repeat_star],<mod>|questionmark,[make_optional],<mod>
|
||||
repeat->copen,<number>,[repeat_exactly],cclose
|
||||
repeat->copen,<number>,comma,[repeat_at_least],cclose,<mod>
|
||||
repeat->copen,<number>,comma,<number>,[repeat_ab],cclose,<mod>
|
||||
|
||||
mod->epsilon | questionmark,[make_lazy] | plus,[make_possessive]
|
||||
|
||||
number->num,[create_number],<number2>
|
||||
number2->epsilon | num,[push_number],<number2>
|
||||
|
||||
preblock->open,[prepare_capture],<block>
|
||||
|
||||
block-><content_in_capture>,[make_capture],close
|
||||
block->questionmark,<mode_switch>
|
||||
block->questionmark,angle_close,[reset_capture],[start_atomic],<content_in_capture>,[make_atomic],close
|
||||
block->questionmark,equal_sign,[reset_capture],[start_lookahead_positive],<content_in_capture>,[look_finish],close
|
||||
block->questionmark,angle_open,equal_sign,[reset_capture],[start_lookbehind_positive],<content_in_capture>,[look_finish],close
|
||||
block->questionmark,exclamation_mark,[reset_capture],[start_lookahead_negative],<content_in_capture>,[look_finish],close
|
||||
block->questionmark,angle_open,exclamation_mark,[reset_capture],[start_lookbehind_negative],<content_in_capture>,[look_finish],close
|
||||
block->questionmark,colon,[reset_capture],<content_in_capture>,close
|
||||
block->questionmark,angle_open,<block_name>,angle_close,<content_in_capture>,[make_capture_with_name],close
|
||||
|
||||
block_name->alpha_characters,[push_name],<block_name2>
|
||||
block_name2->alphanum_characters,[push_name],<block_name2>|epsilon
|
||||
|
||||
mode_switch->i,[mode_case_insensitive],<mode_switch2>
|
||||
mode_switch->c,[mode_case_sensitive],<mode_switch2>
|
||||
mode_switch->s,[mode_singleline],<mode_switch2>
|
||||
mode_switch->m,[mode_multiline],<mode_switch2>
|
||||
mode_switch2->close | <mode_switch>
|
||||
|
||||
character_class->sopen,<set>,[set_make],sclose|sopen,caret,<set2a>,[set_make_negative],sclose
|
||||
set-><setitem>,[set_start],<set2b>
|
||||
set2a-><setitem2>,[set_start],<set2b>|epsilon
|
||||
set2b-><setitem2>,[set_combine],<set2b>|epsilon
|
||||
|
||||
class_named->sopen,colon,<class_named_name>,colon,sclose | sopen,colon,caret,<class_named_name>,[negate_class_named],colon,sclose
|
||||
class_named_name->"alnum",[class_named_alnum]
|
||||
class_named_name->"alpha",[class_named_alpha]
|
||||
class_named_name->"ascii",[class_named_ascii]
|
||||
class_named_name->"blank",[class_named_blank]
|
||||
class_named_name->"cntrl",[class_named_cntrl]
|
||||
class_named_name->"digit",[class_named_digit]
|
||||
class_named_name->"graph",[class_named_graph]
|
||||
class_named_name->"lower",[class_named_lower]
|
||||
class_named_name->"print",[class_named_print]
|
||||
class_named_name->"punct",[class_named_punct]
|
||||
class_named_name->"space",[class_named_space]
|
||||
class_named_name->"upper",[class_named_upper]
|
||||
class_named_name->"word",[class_named_word]
|
||||
class_named_name->"xdigit",[class_named_xdigit]
|
||||
|
||||
|
||||
setitem->other,[push_character],<range> | nonspecial_characters,[push_character],<range> | nonspecial_characters_in_class,[push_character],<range>
|
||||
setitem-><class_named>,<range>
|
||||
setitem->backslash,<backslash_range>,<range> | backslash,<backslash_set>
|
||||
|
||||
setitem2->other,[push_character],<range> | nonspecial_characters,[push_character],<range> | nonspecial_characters_in_class,[push_character],<range>
|
||||
setitem2->caret,[push_character],<range>
|
||||
setitem2-><class_named>,<range>
|
||||
setitem2->backslash,<backslash_range>,<range> | backslash,<backslash_set>
|
||||
|
||||
|
||||
range->epsilon
|
||||
range->minus,other,[push_character],[make_range]|minus,nonspecial_characters,[push_character],[make_range]
|
||||
range->minus,backslash,<backslash_range>,[make_range]|minus,nonspecial_characters_in_class,[push_character],[make_range]
|
||||
range->minus,caret,[push_character],[make_range]
|
||||
|
||||
# backslash range can be used in range match
|
||||
backslash_range-><special>,[push_character]
|
||||
special->dot|sopen|sclose|copen|cclose|open|close|backslash|star|plus|questionmark|pipe|caret|dolar|minus|slash
|
||||
|
||||
hexdec_repeat->hexdec,[push_hexdec],<hexdec_repeat>|epsilon
|
||||
|
||||
backslash_range->u,[create_hexdec],hexdec,[push_hexdec],hexdec,[push_hexdec],hexdec,[push_hexdec],hexdec,[push_hexdec],[finish_hexdec]
|
||||
backslash_range->u,[create_hexdec],copen,hexdec,[push_hexdec],<hexdec_repeat>,cclose,[finish_hexdec]
|
||||
backslash_range->x,[create_hexdec],hexdec,[push_hexdec],hexdec,[push_hexdec],[finish_hexdec]
|
||||
backslash_range->x,[create_hexdec],copen,hexdec,[push_hexdec],<hexdec_repeat>,cclose,[finish_hexdec]
|
||||
backslash_range->n,[push_character_newline]
|
||||
backslash_range->t,[push_character_tab]
|
||||
backslash_range->r,[push_character_return_carriage]
|
||||
backslash_range->0,[push_character_null]
|
||||
backslash_range->a,[push_character_alarm]
|
||||
backslash_range->e,[push_character_escape]
|
||||
backslash_range->f,[push_character_formfeed]
|
||||
backslash_range->minus,[push_character]
|
||||
backslash_range->doublequote,[push_character]
|
||||
backslash_range->angle_open,[push_character]
|
||||
backslash_range->angle_close,[push_character]
|
||||
|
||||
# sets generates a set of matches and can't be used in range
|
||||
backslash_set->d,[class_digit]|D,[class_nondigit]
|
||||
backslash_set->w,[class_word]|W,[class_nonword]
|
||||
backslash_set->N,[class_nonnewline]
|
||||
backslash_set->s,[class_space]|S,[class_nonspace]
|
||||
backslash_set->v,[class_vertical_space]|V,[class_non_vertical_space]
|
||||
backslash_set->h,[class_horizontal_space]|H,[class_non_horizontal_space]
|
||||
backslash_set->p,copen,<property_name>,cclose,[make_property]
|
||||
backslash_set->P,copen,<property_name>,cclose,[make_property_negative]
|
||||
|
||||
# plain backslash can be used only outside of character set
|
||||
backslash->A,[push_assert_subject_begin]
|
||||
backslash->z,[push_assert_subject_end]
|
||||
backslash->Z,[push_assert_subject_end_with_lineend]
|
||||
backslash->b,[push_word_boundary]
|
||||
backslash->B,[push_not_word_boundary]
|
||||
|
||||
property_name->alphanum_characters,[push_property_name],<property_name2>
|
||||
property_name->dot,[push_property_name],<property_name2>
|
||||
property_name2->alphanum_characters,[push_property_name],<property_name2>|epsilon|equal_sign,<property_value>
|
||||
property_name2->dot,[push_property_name],<property_name2>|epsilon|equal_sign,<property_value>
|
||||
|
||||
property_value->alphanum_characters,[push_property_value],<property_value2>
|
||||
property_value->dot,[push_property_value],<property_value2>
|
||||
property_value2->alphanum_characters,[push_property_value],<property_value2>|epsilon
|
||||
property_value2->dot,[push_property_value],<property_value2>|epsilon
|
||||
|
||||
backslash-><backslash_range>|<backslash_set>
|
||||
|
||||
backslash->g,copen,minus,<number>,cclose,[make_relative_back_reference]
|
||||
backslash->g,copen,<number>,cclose,[make_back_reference]
|
||||
backslash->g,copen,<block_name>,cclose,[make_back_reference]
|
||||
backslash->escape_backreference,[create_number],[make_back_reference]
|
||||
|
||||
character->other,[push_character] | nonspecial_characters,[push_character] | set_control_chars,[push_character] | dot,[push_character_anything] | backslash,<backslash>|capture_control_chars,[push_character] | \>,[push_character]
|
||||
|
||||
character_in_capture-><character>
|
||||
|
||||
asserts->caret,[push_assert_begin] | dolar,[push_assert_end]
|
||||
|
||||
|
|
@ -0,0 +1,466 @@
|
|||
#ifndef CTRE__PCRE__HPP
|
||||
#define CTRE__PCRE__HPP
|
||||
|
||||
// THIS FILE WAS GENERATED BY DESATOMAT TOOL, DO NOT MODIFY THIS FILE
|
||||
|
||||
#include "../ctll/grammars.hpp"
|
||||
|
||||
namespace ctre {
|
||||
|
||||
struct pcre {
|
||||
|
||||
// NONTERMINALS:
|
||||
struct a {};
|
||||
struct b {};
|
||||
struct backslash {};
|
||||
struct backslash_range {};
|
||||
struct block {};
|
||||
struct block_name2 {};
|
||||
struct block_name {};
|
||||
struct c {};
|
||||
struct class_named_name {};
|
||||
struct content2 {};
|
||||
struct content_in_capture {};
|
||||
struct content_or_empty {};
|
||||
struct d {};
|
||||
struct e {};
|
||||
struct f {};
|
||||
struct g {};
|
||||
struct h {};
|
||||
struct hexdec_repeat {};
|
||||
struct i {};
|
||||
struct j {};
|
||||
struct k {};
|
||||
struct l {};
|
||||
struct m {};
|
||||
struct mod {};
|
||||
struct mode_switch2 {};
|
||||
struct n {};
|
||||
struct number2 {};
|
||||
struct number {};
|
||||
struct o {};
|
||||
struct opt_content {};
|
||||
struct p {};
|
||||
struct property_name2 {};
|
||||
struct property_name {};
|
||||
struct property_value2 {};
|
||||
struct property_value {};
|
||||
struct range {};
|
||||
struct repeat {};
|
||||
struct s {}; using _start = s;
|
||||
struct set2a {};
|
||||
struct set2b {};
|
||||
struct string2 {};
|
||||
|
||||
// 'action' types:
|
||||
struct class_digit: ctll::action {};
|
||||
struct class_horizontal_space: ctll::action {};
|
||||
struct class_named_alnum: ctll::action {};
|
||||
struct class_named_alpha: ctll::action {};
|
||||
struct class_named_ascii: ctll::action {};
|
||||
struct class_named_blank: ctll::action {};
|
||||
struct class_named_cntrl: ctll::action {};
|
||||
struct class_named_digit: ctll::action {};
|
||||
struct class_named_graph: ctll::action {};
|
||||
struct class_named_lower: ctll::action {};
|
||||
struct class_named_print: ctll::action {};
|
||||
struct class_named_punct: ctll::action {};
|
||||
struct class_named_space: ctll::action {};
|
||||
struct class_named_upper: ctll::action {};
|
||||
struct class_named_word: ctll::action {};
|
||||
struct class_named_xdigit: ctll::action {};
|
||||
struct class_non_horizontal_space: ctll::action {};
|
||||
struct class_non_vertical_space: ctll::action {};
|
||||
struct class_nondigit: ctll::action {};
|
||||
struct class_nonnewline: ctll::action {};
|
||||
struct class_nonspace: ctll::action {};
|
||||
struct class_nonword: ctll::action {};
|
||||
struct class_space: ctll::action {};
|
||||
struct class_vertical_space: ctll::action {};
|
||||
struct class_word: ctll::action {};
|
||||
struct create_hexdec: ctll::action {};
|
||||
struct create_number: ctll::action {};
|
||||
struct finish_hexdec: ctll::action {};
|
||||
struct look_finish: ctll::action {};
|
||||
struct make_alternate: ctll::action {};
|
||||
struct make_atomic: ctll::action {};
|
||||
struct make_back_reference: ctll::action {};
|
||||
struct make_capture: ctll::action {};
|
||||
struct make_capture_with_name: ctll::action {};
|
||||
struct make_lazy: ctll::action {};
|
||||
struct make_optional: ctll::action {};
|
||||
struct make_possessive: ctll::action {};
|
||||
struct make_property: ctll::action {};
|
||||
struct make_property_negative: ctll::action {};
|
||||
struct make_range: ctll::action {};
|
||||
struct make_relative_back_reference: ctll::action {};
|
||||
struct make_sequence: ctll::action {};
|
||||
struct mode_case_insensitive: ctll::action {};
|
||||
struct mode_case_sensitive: ctll::action {};
|
||||
struct mode_multiline: ctll::action {};
|
||||
struct mode_singleline: ctll::action {};
|
||||
struct negate_class_named: ctll::action {};
|
||||
struct prepare_capture: ctll::action {};
|
||||
struct push_assert_begin: ctll::action {};
|
||||
struct push_assert_end: ctll::action {};
|
||||
struct push_assert_subject_begin: ctll::action {};
|
||||
struct push_assert_subject_end: ctll::action {};
|
||||
struct push_assert_subject_end_with_lineend: ctll::action {};
|
||||
struct push_character: ctll::action {};
|
||||
struct push_character_alarm: ctll::action {};
|
||||
struct push_character_anything: ctll::action {};
|
||||
struct push_character_escape: ctll::action {};
|
||||
struct push_character_formfeed: ctll::action {};
|
||||
struct push_character_newline: ctll::action {};
|
||||
struct push_character_null: ctll::action {};
|
||||
struct push_character_return_carriage: ctll::action {};
|
||||
struct push_character_tab: ctll::action {};
|
||||
struct push_empty: ctll::action {};
|
||||
struct push_hexdec: ctll::action {};
|
||||
struct push_name: ctll::action {};
|
||||
struct push_not_word_boundary: ctll::action {};
|
||||
struct push_number: ctll::action {};
|
||||
struct push_property_name: ctll::action {};
|
||||
struct push_property_value: ctll::action {};
|
||||
struct push_word_boundary: ctll::action {};
|
||||
struct repeat_ab: ctll::action {};
|
||||
struct repeat_at_least: ctll::action {};
|
||||
struct repeat_exactly: ctll::action {};
|
||||
struct repeat_plus: ctll::action {};
|
||||
struct repeat_star: ctll::action {};
|
||||
struct reset_capture: ctll::action {};
|
||||
struct set_combine: ctll::action {};
|
||||
struct set_make: ctll::action {};
|
||||
struct set_make_negative: ctll::action {};
|
||||
struct set_start: ctll::action {};
|
||||
struct start_atomic: ctll::action {};
|
||||
struct start_lookahead_negative: ctll::action {};
|
||||
struct start_lookahead_positive: ctll::action {};
|
||||
struct start_lookbehind_negative: ctll::action {};
|
||||
struct start_lookbehind_positive: ctll::action {};
|
||||
|
||||
// (q)LL1 function:
|
||||
using _others = ctll::neg_set<'!','$','\x28','\x29','*','+',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\','\"',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D'>;
|
||||
static constexpr auto rule(s, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>;
|
||||
static constexpr auto rule(s, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>;
|
||||
static constexpr auto rule(s, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2>;
|
||||
static constexpr auto rule(s, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2>;
|
||||
static constexpr auto rule(s, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2>;
|
||||
static constexpr auto rule(s, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"',']','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
|
||||
static constexpr auto rule(s, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
|
||||
static constexpr auto rule(s, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2>;
|
||||
static constexpr auto rule(s, ctll::term<'|'>) -> ctll::push<ctll::anything, push_empty, opt_content, make_alternate>;
|
||||
static constexpr auto rule(s, ctll::epsilon) -> ctll::push<push_empty>;
|
||||
static constexpr auto rule(s, ctll::set<'\x29','*','+','?','\x7B','\x7D'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(a, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"',']','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2, make_alternate>;
|
||||
static constexpr auto rule(a, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::term<'\x29'>) -> ctll::push<push_empty, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::epsilon) -> ctll::push<push_empty, make_alternate>;
|
||||
static constexpr auto rule(a, ctll::set<'*','+','?','\x7B','|','\x7D'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(b, ctll::term<','>) -> ctll::push<ctll::anything, n>;
|
||||
static constexpr auto rule(b, ctll::term<'\x7D'>) -> ctll::push<repeat_exactly, ctll::anything>;
|
||||
|
||||
static constexpr auto rule(backslash, ctll::term<'d'>) -> ctll::push<ctll::anything, class_digit>;
|
||||
static constexpr auto rule(backslash, ctll::term<'h'>) -> ctll::push<ctll::anything, class_horizontal_space>;
|
||||
static constexpr auto rule(backslash, ctll::term<'H'>) -> ctll::push<ctll::anything, class_non_horizontal_space>;
|
||||
static constexpr auto rule(backslash, ctll::term<'V'>) -> ctll::push<ctll::anything, class_non_vertical_space>;
|
||||
static constexpr auto rule(backslash, ctll::term<'D'>) -> ctll::push<ctll::anything, class_nondigit>;
|
||||
static constexpr auto rule(backslash, ctll::term<'N'>) -> ctll::push<ctll::anything, class_nonnewline>;
|
||||
static constexpr auto rule(backslash, ctll::term<'S'>) -> ctll::push<ctll::anything, class_nonspace>;
|
||||
static constexpr auto rule(backslash, ctll::term<'W'>) -> ctll::push<ctll::anything, class_nonword>;
|
||||
static constexpr auto rule(backslash, ctll::term<'s'>) -> ctll::push<ctll::anything, class_space>;
|
||||
static constexpr auto rule(backslash, ctll::term<'v'>) -> ctll::push<ctll::anything, class_vertical_space>;
|
||||
static constexpr auto rule(backslash, ctll::term<'w'>) -> ctll::push<ctll::anything, class_word>;
|
||||
static constexpr auto rule(backslash, ctll::set<'1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, make_back_reference>;
|
||||
static constexpr auto rule(backslash, ctll::term<'g'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, m>;
|
||||
static constexpr auto rule(backslash, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property>;
|
||||
static constexpr auto rule(backslash, ctll::term<'P'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property_negative>;
|
||||
static constexpr auto rule(backslash, ctll::term<'u'>) -> ctll::push<ctll::anything, k>;
|
||||
static constexpr auto rule(backslash, ctll::term<'x'>) -> ctll::push<ctll::anything, l>;
|
||||
static constexpr auto rule(backslash, ctll::term<'A'>) -> ctll::push<ctll::anything, push_assert_subject_begin>;
|
||||
static constexpr auto rule(backslash, ctll::term<'z'>) -> ctll::push<ctll::anything, push_assert_subject_end>;
|
||||
static constexpr auto rule(backslash, ctll::term<'Z'>) -> ctll::push<ctll::anything, push_assert_subject_end_with_lineend>;
|
||||
static constexpr auto rule(backslash, ctll::set<'$','\x28','\x29','*','+','-','.','/','<','>','?','[','\\','\"',']','^','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character>;
|
||||
static constexpr auto rule(backslash, ctll::term<'a'>) -> ctll::push<ctll::anything, push_character_alarm>;
|
||||
static constexpr auto rule(backslash, ctll::term<'e'>) -> ctll::push<ctll::anything, push_character_escape>;
|
||||
static constexpr auto rule(backslash, ctll::term<'f'>) -> ctll::push<ctll::anything, push_character_formfeed>;
|
||||
static constexpr auto rule(backslash, ctll::term<'n'>) -> ctll::push<ctll::anything, push_character_newline>;
|
||||
static constexpr auto rule(backslash, ctll::term<'0'>) -> ctll::push<ctll::anything, push_character_null>;
|
||||
static constexpr auto rule(backslash, ctll::term<'r'>) -> ctll::push<ctll::anything, push_character_return_carriage>;
|
||||
static constexpr auto rule(backslash, ctll::term<'t'>) -> ctll::push<ctll::anything, push_character_tab>;
|
||||
static constexpr auto rule(backslash, ctll::term<'B'>) -> ctll::push<ctll::anything, push_not_word_boundary>;
|
||||
static constexpr auto rule(backslash, ctll::term<'b'>) -> ctll::push<ctll::anything, push_word_boundary>;
|
||||
|
||||
static constexpr auto rule(backslash_range, ctll::term<'u'>) -> ctll::push<ctll::anything, k>;
|
||||
static constexpr auto rule(backslash_range, ctll::term<'x'>) -> ctll::push<ctll::anything, l>;
|
||||
static constexpr auto rule(backslash_range, ctll::set<'$','\x28','\x29','*','+','-','.','/','<','>','?','[','\\','\"',']','^','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character>;
|
||||
static constexpr auto rule(backslash_range, ctll::term<'a'>) -> ctll::push<ctll::anything, push_character_alarm>;
|
||||
static constexpr auto rule(backslash_range, ctll::term<'e'>) -> ctll::push<ctll::anything, push_character_escape>;
|
||||
static constexpr auto rule(backslash_range, ctll::term<'f'>) -> ctll::push<ctll::anything, push_character_formfeed>;
|
||||
static constexpr auto rule(backslash_range, ctll::term<'n'>) -> ctll::push<ctll::anything, push_character_newline>;
|
||||
static constexpr auto rule(backslash_range, ctll::term<'0'>) -> ctll::push<ctll::anything, push_character_null>;
|
||||
static constexpr auto rule(backslash_range, ctll::term<'r'>) -> ctll::push<ctll::anything, push_character_return_carriage>;
|
||||
static constexpr auto rule(backslash_range, ctll::term<'t'>) -> ctll::push<ctll::anything, push_character_tab>;
|
||||
|
||||
static constexpr auto rule(block, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, ctll::term<'?'>) -> ctll::push<ctll::anything, d>;
|
||||
static constexpr auto rule(block, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"',']','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, ctll::term<'|'>) -> ctll::push<ctll::anything, push_empty, content_or_empty, make_alternate, make_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(block, ctll::term<'\x29'>) -> ctll::push<push_empty, make_capture, ctll::anything>;
|
||||
static constexpr auto rule(block, ctll::set<'*','+','\x7B','\x7D'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(block_name2, ctll::set<'>','\x7D'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(block_name2, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_name, block_name2>;
|
||||
|
||||
static constexpr auto rule(block_name, ctll::set<'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_name, block_name2>;
|
||||
|
||||
static constexpr auto rule(c, ctll::term<'['>) -> ctll::push<ctll::anything, ctll::term<':'>, i, range, set_start, set2b, set_make, ctll::term<']'>>;
|
||||
static constexpr auto rule(c, ctll::term<'\\'>) -> ctll::push<ctll::anything, e, set_start, set2b, set_make, ctll::term<']'>>;
|
||||
static constexpr auto rule(c, ctll::set<'!','$','\x28','\x29','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character, range, set_start, set2b, set_make, ctll::term<']'>>;
|
||||
static constexpr auto rule(c, _others) -> ctll::push<ctll::anything, push_character, range, set_start, set2b, set_make, ctll::term<']'>>;
|
||||
static constexpr auto rule(c, ctll::term<'^'>) -> ctll::push<ctll::anything, set2a, set_make_negative, ctll::term<']'>>;
|
||||
static constexpr auto rule(c, ctll::set<'-',']'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(class_named_name, ctll::term<'x'>) -> ctll::push<ctll::anything, ctll::term<'d'>, ctll::term<'i'>, ctll::term<'g'>, ctll::term<'i'>, ctll::term<'t'>, class_named_xdigit>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'d'>) -> ctll::push<ctll::anything, ctll::term<'i'>, ctll::term<'g'>, ctll::term<'i'>, ctll::term<'t'>, class_named_digit>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'b'>) -> ctll::push<ctll::anything, ctll::term<'l'>, ctll::term<'a'>, ctll::term<'n'>, ctll::term<'k'>, class_named_blank>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'c'>) -> ctll::push<ctll::anything, ctll::term<'n'>, ctll::term<'t'>, ctll::term<'r'>, ctll::term<'l'>, class_named_cntrl>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'w'>) -> ctll::push<ctll::anything, ctll::term<'o'>, ctll::term<'r'>, ctll::term<'d'>, class_named_word>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'l'>) -> ctll::push<ctll::anything, ctll::term<'o'>, ctll::term<'w'>, ctll::term<'e'>, ctll::term<'r'>, class_named_lower>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'s'>) -> ctll::push<ctll::anything, ctll::term<'p'>, ctll::term<'a'>, ctll::term<'c'>, ctll::term<'e'>, class_named_space>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'u'>) -> ctll::push<ctll::anything, ctll::term<'p'>, ctll::term<'p'>, ctll::term<'e'>, ctll::term<'r'>, class_named_upper>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'g'>) -> ctll::push<ctll::anything, ctll::term<'r'>, ctll::term<'a'>, ctll::term<'p'>, ctll::term<'h'>, class_named_graph>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'a'>) -> ctll::push<ctll::anything, g>;
|
||||
static constexpr auto rule(class_named_name, ctll::term<'p'>) -> ctll::push<ctll::anything, h>;
|
||||
|
||||
static constexpr auto rule(content2, ctll::term<'\x29'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(content2, ctll::epsilon) -> ctll::epsilon;
|
||||
static constexpr auto rule(content2, ctll::term<'|'>) -> ctll::push<ctll::anything, a>;
|
||||
|
||||
static constexpr auto rule(content_in_capture, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_in_capture, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_in_capture, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_in_capture, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_in_capture, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_in_capture, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"',']','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_in_capture, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_in_capture, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_in_capture, ctll::term<'|'>) -> ctll::push<ctll::anything, push_empty, content_or_empty, make_alternate>;
|
||||
static constexpr auto rule(content_in_capture, ctll::term<'\x29'>) -> ctll::push<push_empty>;
|
||||
static constexpr auto rule(content_in_capture, ctll::set<'*','+','?','\x7B','\x7D'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(content_or_empty, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_or_empty, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_or_empty, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_or_empty, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_or_empty, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_or_empty, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"',']','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_or_empty, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_or_empty, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2>;
|
||||
static constexpr auto rule(content_or_empty, ctll::term<'\x29'>) -> ctll::push<push_empty>;
|
||||
static constexpr auto rule(content_or_empty, ctll::set<'*','+','?','\x7B','|','\x7D'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(d, ctll::term<'i'>) -> ctll::push<ctll::anything, mode_case_insensitive, mode_switch2>;
|
||||
static constexpr auto rule(d, ctll::term<'c'>) -> ctll::push<ctll::anything, mode_case_sensitive, mode_switch2>;
|
||||
static constexpr auto rule(d, ctll::term<'m'>) -> ctll::push<ctll::anything, mode_multiline, mode_switch2>;
|
||||
static constexpr auto rule(d, ctll::term<'s'>) -> ctll::push<ctll::anything, mode_singleline, mode_switch2>;
|
||||
static constexpr auto rule(d, ctll::term<'<'>) -> ctll::push<ctll::anything, o>;
|
||||
static constexpr auto rule(d, ctll::term<':'>) -> ctll::push<ctll::anything, reset_capture, content_in_capture, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(d, ctll::term<'>'>) -> ctll::push<ctll::anything, reset_capture, start_atomic, content_in_capture, make_atomic, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(d, ctll::term<'!'>) -> ctll::push<ctll::anything, reset_capture, start_lookahead_negative, content_in_capture, look_finish, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(d, ctll::term<'='>) -> ctll::push<ctll::anything, reset_capture, start_lookahead_positive, content_in_capture, look_finish, ctll::term<'\x29'>>;
|
||||
|
||||
static constexpr auto rule(e, ctll::term<'d'>) -> ctll::push<ctll::anything, class_digit>;
|
||||
static constexpr auto rule(e, ctll::term<'h'>) -> ctll::push<ctll::anything, class_horizontal_space>;
|
||||
static constexpr auto rule(e, ctll::term<'H'>) -> ctll::push<ctll::anything, class_non_horizontal_space>;
|
||||
static constexpr auto rule(e, ctll::term<'V'>) -> ctll::push<ctll::anything, class_non_vertical_space>;
|
||||
static constexpr auto rule(e, ctll::term<'D'>) -> ctll::push<ctll::anything, class_nondigit>;
|
||||
static constexpr auto rule(e, ctll::term<'N'>) -> ctll::push<ctll::anything, class_nonnewline>;
|
||||
static constexpr auto rule(e, ctll::term<'S'>) -> ctll::push<ctll::anything, class_nonspace>;
|
||||
static constexpr auto rule(e, ctll::term<'W'>) -> ctll::push<ctll::anything, class_nonword>;
|
||||
static constexpr auto rule(e, ctll::term<'s'>) -> ctll::push<ctll::anything, class_space>;
|
||||
static constexpr auto rule(e, ctll::term<'v'>) -> ctll::push<ctll::anything, class_vertical_space>;
|
||||
static constexpr auto rule(e, ctll::term<'w'>) -> ctll::push<ctll::anything, class_word>;
|
||||
static constexpr auto rule(e, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property>;
|
||||
static constexpr auto rule(e, ctll::term<'P'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property_negative>;
|
||||
static constexpr auto rule(e, ctll::term<'u'>) -> ctll::push<ctll::anything, k, range>;
|
||||
static constexpr auto rule(e, ctll::term<'x'>) -> ctll::push<ctll::anything, l, range>;
|
||||
static constexpr auto rule(e, ctll::set<'$','\x28','\x29','*','+','-','.','/','<','>','?','[','\\','\"',']','^','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character, range>;
|
||||
static constexpr auto rule(e, ctll::term<'a'>) -> ctll::push<ctll::anything, push_character_alarm, range>;
|
||||
static constexpr auto rule(e, ctll::term<'e'>) -> ctll::push<ctll::anything, push_character_escape, range>;
|
||||
static constexpr auto rule(e, ctll::term<'f'>) -> ctll::push<ctll::anything, push_character_formfeed, range>;
|
||||
static constexpr auto rule(e, ctll::term<'n'>) -> ctll::push<ctll::anything, push_character_newline, range>;
|
||||
static constexpr auto rule(e, ctll::term<'0'>) -> ctll::push<ctll::anything, push_character_null, range>;
|
||||
static constexpr auto rule(e, ctll::term<'r'>) -> ctll::push<ctll::anything, push_character_return_carriage, range>;
|
||||
static constexpr auto rule(e, ctll::term<'t'>) -> ctll::push<ctll::anything, push_character_tab, range>;
|
||||
|
||||
static constexpr auto rule(f, ctll::term<'d'>) -> ctll::push<ctll::anything, class_digit>;
|
||||
static constexpr auto rule(f, ctll::term<'h'>) -> ctll::push<ctll::anything, class_horizontal_space>;
|
||||
static constexpr auto rule(f, ctll::term<'H'>) -> ctll::push<ctll::anything, class_non_horizontal_space>;
|
||||
static constexpr auto rule(f, ctll::term<'V'>) -> ctll::push<ctll::anything, class_non_vertical_space>;
|
||||
static constexpr auto rule(f, ctll::term<'D'>) -> ctll::push<ctll::anything, class_nondigit>;
|
||||
static constexpr auto rule(f, ctll::term<'N'>) -> ctll::push<ctll::anything, class_nonnewline>;
|
||||
static constexpr auto rule(f, ctll::term<'S'>) -> ctll::push<ctll::anything, class_nonspace>;
|
||||
static constexpr auto rule(f, ctll::term<'W'>) -> ctll::push<ctll::anything, class_nonword>;
|
||||
static constexpr auto rule(f, ctll::term<'s'>) -> ctll::push<ctll::anything, class_space>;
|
||||
static constexpr auto rule(f, ctll::term<'v'>) -> ctll::push<ctll::anything, class_vertical_space>;
|
||||
static constexpr auto rule(f, ctll::term<'w'>) -> ctll::push<ctll::anything, class_word>;
|
||||
static constexpr auto rule(f, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property>;
|
||||
static constexpr auto rule(f, ctll::term<'P'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property_negative>;
|
||||
static constexpr auto rule(f, ctll::term<'u'>) -> ctll::push<ctll::anything, k, range>;
|
||||
static constexpr auto rule(f, ctll::term<'x'>) -> ctll::push<ctll::anything, l, range>;
|
||||
static constexpr auto rule(f, ctll::set<'$','\x28','\x29','*','+','-','.','/','<','>','?','[','\\','\"',']','^','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character, range>;
|
||||
static constexpr auto rule(f, ctll::term<'a'>) -> ctll::push<ctll::anything, push_character_alarm, range>;
|
||||
static constexpr auto rule(f, ctll::term<'e'>) -> ctll::push<ctll::anything, push_character_escape, range>;
|
||||
static constexpr auto rule(f, ctll::term<'f'>) -> ctll::push<ctll::anything, push_character_formfeed, range>;
|
||||
static constexpr auto rule(f, ctll::term<'n'>) -> ctll::push<ctll::anything, push_character_newline, range>;
|
||||
static constexpr auto rule(f, ctll::term<'0'>) -> ctll::push<ctll::anything, push_character_null, range>;
|
||||
static constexpr auto rule(f, ctll::term<'r'>) -> ctll::push<ctll::anything, push_character_return_carriage, range>;
|
||||
static constexpr auto rule(f, ctll::term<'t'>) -> ctll::push<ctll::anything, push_character_tab, range>;
|
||||
|
||||
static constexpr auto rule(g, ctll::term<'s'>) -> ctll::push<ctll::anything, ctll::term<'c'>, ctll::term<'i'>, ctll::term<'i'>, class_named_ascii>;
|
||||
static constexpr auto rule(g, ctll::term<'l'>) -> ctll::push<ctll::anything, p>;
|
||||
|
||||
static constexpr auto rule(h, ctll::term<'r'>) -> ctll::push<ctll::anything, ctll::term<'i'>, ctll::term<'n'>, ctll::term<'t'>, class_named_print>;
|
||||
static constexpr auto rule(h, ctll::term<'u'>) -> ctll::push<ctll::anything, ctll::term<'n'>, ctll::term<'c'>, ctll::term<'t'>, class_named_punct>;
|
||||
|
||||
static constexpr auto rule(hexdec_repeat, ctll::term<'\x7D'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(hexdec_repeat, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>) -> ctll::push<ctll::anything, push_hexdec, hexdec_repeat>;
|
||||
|
||||
static constexpr auto rule(i, ctll::term<'^'>) -> ctll::push<ctll::anything, class_named_name, negate_class_named, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'x'>) -> ctll::push<ctll::anything, ctll::term<'d'>, ctll::term<'i'>, ctll::term<'g'>, ctll::term<'i'>, ctll::term<'t'>, class_named_xdigit, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'d'>) -> ctll::push<ctll::anything, ctll::term<'i'>, ctll::term<'g'>, ctll::term<'i'>, ctll::term<'t'>, class_named_digit, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'b'>) -> ctll::push<ctll::anything, ctll::term<'l'>, ctll::term<'a'>, ctll::term<'n'>, ctll::term<'k'>, class_named_blank, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'c'>) -> ctll::push<ctll::anything, ctll::term<'n'>, ctll::term<'t'>, ctll::term<'r'>, ctll::term<'l'>, class_named_cntrl, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'w'>) -> ctll::push<ctll::anything, ctll::term<'o'>, ctll::term<'r'>, ctll::term<'d'>, class_named_word, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'l'>) -> ctll::push<ctll::anything, ctll::term<'o'>, ctll::term<'w'>, ctll::term<'e'>, ctll::term<'r'>, class_named_lower, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'s'>) -> ctll::push<ctll::anything, ctll::term<'p'>, ctll::term<'a'>, ctll::term<'c'>, ctll::term<'e'>, class_named_space, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'u'>) -> ctll::push<ctll::anything, ctll::term<'p'>, ctll::term<'p'>, ctll::term<'e'>, ctll::term<'r'>, class_named_upper, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'g'>) -> ctll::push<ctll::anything, ctll::term<'r'>, ctll::term<'a'>, ctll::term<'p'>, ctll::term<'h'>, class_named_graph, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'a'>) -> ctll::push<ctll::anything, g, ctll::term<':'>, ctll::term<']'>>;
|
||||
static constexpr auto rule(i, ctll::term<'p'>) -> ctll::push<ctll::anything, h, ctll::term<':'>, ctll::term<']'>>;
|
||||
|
||||
static constexpr auto rule(j, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash_range, make_range>;
|
||||
static constexpr auto rule(j, ctll::set<'!','$','\x28','\x29','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character, make_range>;
|
||||
static constexpr auto rule(j, _others) -> ctll::push<ctll::anything, push_character, make_range>;
|
||||
static constexpr auto rule(j, ctll::set<'-','[',']'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(k, ctll::term<'\x7B'>) -> ctll::push<create_hexdec, ctll::anything, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, hexdec_repeat, ctll::term<'\x7D'>, finish_hexdec>;
|
||||
static constexpr auto rule(k, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>) -> ctll::push<create_hexdec, ctll::anything, push_hexdec, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, finish_hexdec>;
|
||||
|
||||
static constexpr auto rule(l, ctll::term<'\x7B'>) -> ctll::push<create_hexdec, ctll::anything, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, hexdec_repeat, ctll::term<'\x7D'>, finish_hexdec>;
|
||||
static constexpr auto rule(l, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>) -> ctll::push<create_hexdec, ctll::anything, push_hexdec, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, finish_hexdec>;
|
||||
|
||||
static constexpr auto rule(m, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, number2, ctll::term<'\x7D'>, make_back_reference>;
|
||||
static constexpr auto rule(m, ctll::term<'-'>) -> ctll::push<ctll::anything, number, ctll::term<'\x7D'>, make_relative_back_reference>;
|
||||
static constexpr auto rule(m, ctll::set<'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_name, block_name2, ctll::term<'\x7D'>, make_back_reference>;
|
||||
|
||||
static constexpr auto rule(mod, ctll::set<'!','$','\x28','\x29',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\','\"',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(mod, ctll::epsilon) -> ctll::epsilon;
|
||||
static constexpr auto rule(mod, _others) -> ctll::epsilon;
|
||||
static constexpr auto rule(mod, ctll::term<'?'>) -> ctll::push<ctll::anything, make_lazy>;
|
||||
static constexpr auto rule(mod, ctll::term<'+'>) -> ctll::push<ctll::anything, make_possessive>;
|
||||
static constexpr auto rule(mod, ctll::set<'*','\x7B','\x7D'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(mode_switch2, ctll::term<'i'>) -> ctll::push<ctll::anything, mode_case_insensitive, mode_switch2>;
|
||||
static constexpr auto rule(mode_switch2, ctll::term<'c'>) -> ctll::push<ctll::anything, mode_case_sensitive, mode_switch2>;
|
||||
static constexpr auto rule(mode_switch2, ctll::term<'m'>) -> ctll::push<ctll::anything, mode_multiline, mode_switch2>;
|
||||
static constexpr auto rule(mode_switch2, ctll::term<'s'>) -> ctll::push<ctll::anything, mode_singleline, mode_switch2>;
|
||||
static constexpr auto rule(mode_switch2, ctll::term<'\x29'>) -> ctll::push<ctll::anything>;
|
||||
|
||||
static constexpr auto rule(n, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<number, repeat_ab, ctll::term<'\x7D'>, mod>;
|
||||
static constexpr auto rule(n, ctll::term<'\x7D'>) -> ctll::push<repeat_at_least, ctll::anything, mod>;
|
||||
|
||||
static constexpr auto rule(number2, ctll::set<',','\x7D'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(number2, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_number, number2>;
|
||||
|
||||
static constexpr auto rule(number, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, number2>;
|
||||
|
||||
static constexpr auto rule(o, ctll::set<'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<block_name, ctll::term<'>'>, content_in_capture, make_capture_with_name, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(o, ctll::term<'!'>) -> ctll::push<ctll::anything, reset_capture, start_lookbehind_negative, content_in_capture, look_finish, ctll::term<'\x29'>>;
|
||||
static constexpr auto rule(o, ctll::term<'='>) -> ctll::push<ctll::anything, reset_capture, start_lookbehind_positive, content_in_capture, look_finish, ctll::term<'\x29'>>;
|
||||
|
||||
static constexpr auto rule(opt_content, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>;
|
||||
static constexpr auto rule(opt_content, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>;
|
||||
static constexpr auto rule(opt_content, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2>;
|
||||
static constexpr auto rule(opt_content, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2>;
|
||||
static constexpr auto rule(opt_content, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2>;
|
||||
static constexpr auto rule(opt_content, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"',']','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
|
||||
static constexpr auto rule(opt_content, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
|
||||
static constexpr auto rule(opt_content, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2>;
|
||||
static constexpr auto rule(opt_content, ctll::epsilon) -> ctll::push<push_empty>;
|
||||
static constexpr auto rule(opt_content, ctll::set<'\x29','*','+','?','\x7B','|','\x7D'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(p, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'h'>, ctll::term<'a'>, class_named_alpha>;
|
||||
static constexpr auto rule(p, ctll::term<'n'>) -> ctll::push<ctll::anything, ctll::term<'u'>, ctll::term<'m'>, class_named_alnum>;
|
||||
|
||||
static constexpr auto rule(property_name2, ctll::term<'\x7D'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(property_name2, ctll::term<'='>) -> ctll::push<ctll::anything, property_value>;
|
||||
static constexpr auto rule(property_name2, ctll::set<'.','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_property_name, property_name2>;
|
||||
|
||||
static constexpr auto rule(property_name, ctll::set<'.','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_property_name, property_name2>;
|
||||
|
||||
static constexpr auto rule(property_value2, ctll::term<'\x7D'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(property_value2, ctll::set<'.','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_property_value, property_value2>;
|
||||
|
||||
static constexpr auto rule(property_value, ctll::set<'.','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_property_value, property_value2>;
|
||||
|
||||
static constexpr auto rule(range, ctll::set<'!','$','\x28','\x29','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\','\"',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(range, ctll::epsilon) -> ctll::epsilon;
|
||||
static constexpr auto rule(range, _others) -> ctll::epsilon;
|
||||
static constexpr auto rule(range, ctll::term<'-'>) -> ctll::push<ctll::anything, j>;
|
||||
|
||||
static constexpr auto rule(repeat, ctll::set<'!','$','\x28','\x29',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\','\"',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(repeat, ctll::epsilon) -> ctll::epsilon;
|
||||
static constexpr auto rule(repeat, _others) -> ctll::epsilon;
|
||||
static constexpr auto rule(repeat, ctll::term<'?'>) -> ctll::push<ctll::anything, make_optional, mod>;
|
||||
static constexpr auto rule(repeat, ctll::term<'\x7B'>) -> ctll::push<ctll::anything, number, b>;
|
||||
static constexpr auto rule(repeat, ctll::term<'+'>) -> ctll::push<ctll::anything, repeat_plus, mod>;
|
||||
static constexpr auto rule(repeat, ctll::term<'*'>) -> ctll::push<ctll::anything, repeat_star, mod>;
|
||||
static constexpr auto rule(repeat, ctll::term<'\x7D'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(set2a, ctll::term<']'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(set2a, ctll::term<'['>) -> ctll::push<ctll::anything, ctll::term<':'>, i, range, set_start, set2b>;
|
||||
static constexpr auto rule(set2a, ctll::term<'\\'>) -> ctll::push<ctll::anything, f, set_start, set2b>;
|
||||
static constexpr auto rule(set2a, ctll::set<'!','$','\x28','\x29','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character, range, set_start, set2b>;
|
||||
static constexpr auto rule(set2a, _others) -> ctll::push<ctll::anything, push_character, range, set_start, set2b>;
|
||||
static constexpr auto rule(set2a, ctll::term<'-'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(set2b, ctll::term<']'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(set2b, ctll::term<'['>) -> ctll::push<ctll::anything, ctll::term<':'>, i, range, set_combine, set2b>;
|
||||
static constexpr auto rule(set2b, ctll::term<'\\'>) -> ctll::push<ctll::anything, f, set_combine, set2b>;
|
||||
static constexpr auto rule(set2b, ctll::set<'!','$','\x28','\x29','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character, range, set_combine, set2b>;
|
||||
static constexpr auto rule(set2b, _others) -> ctll::push<ctll::anything, push_character, range, set_combine, set2b>;
|
||||
static constexpr auto rule(set2b, ctll::term<'-'>) -> ctll::reject;
|
||||
|
||||
static constexpr auto rule(string2, ctll::set<'\x29','|'>) -> ctll::epsilon;
|
||||
static constexpr auto rule(string2, ctll::epsilon) -> ctll::epsilon;
|
||||
static constexpr auto rule(string2, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, make_sequence>;
|
||||
static constexpr auto rule(string2, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, make_sequence>;
|
||||
static constexpr auto rule(string2, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, make_sequence>;
|
||||
static constexpr auto rule(string2, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, make_sequence>;
|
||||
static constexpr auto rule(string2, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, make_sequence>;
|
||||
static constexpr auto rule(string2, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','\"',']','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_character, repeat, string2, make_sequence>;
|
||||
static constexpr auto rule(string2, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, make_sequence>;
|
||||
static constexpr auto rule(string2, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, make_sequence>;
|
||||
static constexpr auto rule(string2, ctll::set<'*','+','?','\x7B','\x7D'>) -> ctll::reject;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //CTRE__PCRE__HPP
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef CTRE__PCRE_ACTIONS__HPP
|
||||
#define CTRE__PCRE_ACTIONS__HPP
|
||||
|
||||
#include "pcre.hpp"
|
||||
#include "rotate.hpp"
|
||||
#include "id.hpp"
|
||||
#ifndef CTRE_IN_A_MODULE
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#endif
|
||||
|
||||
namespace ctre {
|
||||
|
||||
template <size_t Counter> struct pcre_parameters {
|
||||
static constexpr size_t current_counter = Counter;
|
||||
};
|
||||
|
||||
template <typename Stack = ctll::list<>, typename Parameters = pcre_parameters<0>, typename Mode = ctll::list<>> struct pcre_context {
|
||||
using stack_type = Stack;
|
||||
using parameters_type = Parameters;
|
||||
using mode_list = Mode;
|
||||
static constexpr inline auto stack = stack_type();
|
||||
static constexpr inline auto parameters = parameters_type();
|
||||
static constexpr inline auto mode = mode_list();
|
||||
constexpr pcre_context() noexcept { }
|
||||
constexpr pcre_context(Stack, Parameters) noexcept { }
|
||||
constexpr pcre_context(Stack, Parameters, Mode) noexcept { }
|
||||
};
|
||||
|
||||
template <typename... Content, typename Parameters> pcre_context(ctll::list<Content...>, Parameters) -> pcre_context<ctll::list<Content...>, Parameters>;
|
||||
|
||||
template <size_t Value> struct number { };
|
||||
|
||||
template <size_t Id> struct capture_id { };
|
||||
|
||||
struct pcre_actions {
|
||||
// i know it's ugly, but it's more readable
|
||||
#include "actions/asserts.inc.hpp"
|
||||
#include "actions/atomic_group.inc.hpp"
|
||||
#include "actions/backreference.inc.hpp"
|
||||
#include "actions/boundaries.inc.hpp"
|
||||
#include "actions/capture.inc.hpp"
|
||||
#include "actions/characters.inc.hpp"
|
||||
#include "actions/class.inc.hpp"
|
||||
#include "actions/fusion.inc.hpp"
|
||||
#include "actions/hexdec.inc.hpp"
|
||||
#include "actions/look.inc.hpp"
|
||||
#include "actions/named_class.inc.hpp"
|
||||
#include "actions/options.inc.hpp"
|
||||
#include "actions/properties.inc.hpp"
|
||||
#include "actions/repeat.inc.hpp"
|
||||
#include "actions/sequence.inc.hpp"
|
||||
#include "actions/set.inc.hpp"
|
||||
#include "actions/mode.inc.hpp"
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
#ifndef CTRE_V2__CTRE__RANGE__HPP
|
||||
#define CTRE_V2__CTRE__RANGE__HPP
|
||||
|
||||
#include "iterators.hpp"
|
||||
|
||||
namespace ctre {
|
||||
|
||||
template <typename> constexpr bool is_range = false;
|
||||
|
||||
template <typename BeginIterator, typename EndIterator, typename RE, typename ResultIterator = BeginIterator> struct regex_range {
|
||||
BeginIterator _begin;
|
||||
EndIterator _end;
|
||||
|
||||
constexpr CTRE_FORCE_INLINE regex_range(BeginIterator begin, EndIterator end) noexcept: _begin{begin}, _end{end} { }
|
||||
|
||||
constexpr CTRE_FORCE_INLINE auto begin() const noexcept {
|
||||
return regex_iterator<BeginIterator, EndIterator, RE, ResultIterator>(_begin, _end);
|
||||
}
|
||||
constexpr CTRE_FORCE_INLINE auto end() const noexcept {
|
||||
return regex_end_iterator{};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Ts> constexpr bool is_range<regex_range<Ts...>> = true;
|
||||
|
||||
template <typename BeginIterator, typename EndIterator, typename RE, typename ResultIterator = BeginIterator> struct regex_split_range {
|
||||
BeginIterator _begin;
|
||||
EndIterator _end;
|
||||
|
||||
constexpr CTRE_FORCE_INLINE regex_split_range(BeginIterator begin, EndIterator end) |